File Coverage

blib/lib/Blockchain/Ethereum/Key.pm
Criterion Covered Total %
statement 51 52 98.0
branch 3 4 75.0
condition 4 6 66.6
subroutine 15 15 100.0
pod 3 5 60.0
total 76 82 92.6


line stmt bran cond sub pod time code
1             package Blockchain::Ethereum::Key;
2              
3 10     10   446840 use v5.26;
  10         34  
4 10     10   63 use strict;
  10         25  
  10         344  
5 10     10   48 use warnings;
  10         16  
  10         801  
6              
7             # ABSTRACT: Ethereum key abstraction
8             our $AUTHORITY = 'cpan:REFECO'; # AUTHORITY
9             our $VERSION = '0.021'; # VERSION
10              
11 10     10   63 use Carp;
  10         27  
  10         809  
12 10     10   2536 use Crypt::Digest::Keccak256 qw(keccak256);
  10         21235  
  10         658  
13 10     10   2652 use Crypt::PRNG qw(random_bytes);
  10         5562  
  10         664  
14 10     10   78 use Scalar::Util qw(blessed);
  10         16  
  10         528  
15 10     10   5448 use Bitcoin::Secp256k1;
  10         192628  
  10         551  
16              
17 10     10   4992 use Blockchain::Ethereum::Address;
  10         44  
  10         4755  
18              
19             sub new {
20 25     25 0 346335 my ($class, %params) = @_;
21 25         105 my $self = bless {}, $class;
22              
23 25 50       100 if (exists $params{private_key}) {
24 25         110 $self->{private_key} = $params{private_key};
25             } else {
26 0         0 $self->{private_key} = random_bytes(32);
27             }
28              
29 25         186 return $self;
30             }
31              
32             sub private_key {
33 22     22 0 3746 return shift->{private_key};
34             }
35              
36             sub _ecc_handler {
37 26   66 26   295 return shift->{ecc_handler} //= Bitcoin::Secp256k1->new;
38             }
39              
40             sub sign_transaction {
41 9     9 1 98 my ($self, $transaction) = @_;
42              
43 9 100 66     324 croak "transaction must be a reference of Blockchain::Ethereum::Transaction"
44             unless blessed $transaction && $transaction->isa('Blockchain::Ethereum::Transaction');
45              
46 8         41 my $result = $self->_ecc_handler->sign_digest_recoverable($self->private_key, $transaction->hash);
47              
48 8         1156 my $r = substr($result->{signature}, 0, 32);
49 8         21 my $s = substr($result->{signature}, 32, 32);
50 8         52 my $recovery_id = $result->{recovery_id};
51              
52 8         92 $transaction->set_r(unpack "H*", $r);
53 8         57 $transaction->set_s(unpack "H*", $s);
54 8         44 $transaction->generate_v($recovery_id);
55              
56 8         35 return $transaction;
57             }
58              
59             sub address {
60 9     9 1 24 my $self = shift;
61              
62 9         34 my $pubkey = $self->_ecc_handler->create_public_key($self->private_key);
63 9         744 my $compressed_pubkey = $self->_ecc_handler->compress_public_key($pubkey, 0);
64 9         272 my $pubkey_64 = substr($compressed_pubkey, 1); # remove 0x04 prefix
65 9         40 my $address = substr(keccak256($pubkey_64), -20);
66 9         156 my $hex_address = unpack("H*", $address);
67              
68 9         68 return Blockchain::Ethereum::Address->new(address => "0x$hex_address");
69             }
70              
71             sub export {
72 5     5 1 26 return shift->private_key;
73             }
74              
75             1;
76              
77             __END__