File Coverage

blib/lib/Blockchain/Ethereum/Keystore/Key/PKUtil.pm
Criterion Covered Total %
statement 11 39 28.2
branch 0 8 0.0
condition n/a
subroutine 4 5 80.0
pod n/a
total 15 52 28.8


line stmt bran cond sub pod time code
1 4     4   77 use v5.26;
  4         18  
2 4     4   38 use Object::Pad;
  4         9  
  4         49  
3              
4             package Blockchain::Ethereum::Keystore::Key::PKUtil 0.005;
5             class Blockchain::Ethereum::Keystore::Key::PKUtil
6 4     4   3010 :isa(Crypt::Perl::ECDSA::PrivateKey);
  4         111735  
  4         290  
7              
8             =encoding utf8
9              
10             =head1 SYNOPSIS
11              
12             This is a child for L<Crypt::Perl::ECDSA::PrivateKey> to overwrite
13             the function _sign that on the parent module returns only C<$r> and C<$s>,
14             this version returns the C<$y_parity> as well, what simplifies signing
15             the transaction.
16              
17             You don't want to use this directly, use instead L<Blockchain::Ethereum::Keystore::Key>
18              
19             =cut;
20              
21 4     4   950 use Carp;
  4         10  
  4         3511  
22              
23             =head2 _sign
24              
25             Overwrites L<Crypt::Perl::ECDSA::PrivateKey> adding the y-parity to the response
26              
27             Usage:
28              
29             _sign($rlp_encoded_transaction) -> (Math::BigInt $r, Math::BigInt $s, $v)
30              
31             =over 4
32              
33             =item * C<message> - Message to be signed
34              
35             =back
36              
37             L<Crypt::Perl::BigInt> r, L<Crypt::Perl::BigInt> s, uint y_parity
38              
39             =cut
40              
41 0     0     method _sign ($message) {
  0            
  0            
  0            
42              
43 0           my $dgst = Crypt::Perl::BigInt->from_bytes($message);
44              
45 0           my $priv_num = $self->{'private'}; # Math::BigInt->from_hex( $priv_hex );
46              
47 0           my $n = $self->_curve()->{'n'};
48              
49 0           my $key_len = $self->max_sign_bits();
50 0           my $dgst_len = $dgst->bit_length();
51 0 0         if ($dgst_len > $key_len) {
52 0           croak Crypt::Perl::X::create('TooLongToSign', $key_len, $dgst_len);
53             }
54              
55             #isa ECPoint
56 0           my $G = $self->_G();
57 0           my ($k, $r, $Q);
58              
59 0           do {
60 0           require Crypt::Perl::ECDSA::Deterministic;
61 0           $k = Crypt::Perl::ECDSA::Deterministic::generate_k($n, $priv_num, $message, 'sha256');
62              
63             # making it external so I can calculate the y parity
64 0           $Q = $G->multiply($k); #$Q isa ECPoint
65              
66 0           $r = $Q->get_x()->to_bigint()->copy()->bmod($n);
67             } while (!$r->is_positive());
68              
69 0           my $s = $k->bmodinv($n);
70              
71             #$s *= ( $dgst + ( $priv_num * $r ) );
72 0           $s->bmul($priv_num->copy()->bmuladd($r, $dgst));
73              
74 0           $s->bmod($n);
75              
76             # y parity calculation
77             # most of the changes unrelated to the parent module are bellow
78 0 0         my $y_parity = ($Q->get_y->to_bigint->is_odd() ? 1 : 0) | ($Q->get_x->to_bigint->bcmp($r) != 0 ? 2 : 0);
    0          
79              
80 0           my $nb2;
81 0           ($nb2, $_) = $n->copy->bdiv(2);
82              
83 0 0         if ($s->bcmp($nb2) > 0) {
84 0           $s = $n->copy->bsub($s);
85 0           $y_parity ^= 1;
86             }
87              
88 0           return ($r, $s, $y_parity);
89             }
90              
91             1;
92              
93             __END__
94              
95             =head1 AUTHOR
96              
97             Reginaldo Costa, C<< <refeco at cpan.org> >>
98              
99             =head1 BUGS
100              
101             Please report any bugs or feature requests to L<https://github.com/refeco/perl-ethereum-keystore>
102              
103             =head1 LICENSE AND COPYRIGHT
104              
105             This software is Copyright (c) 2023 by REFECO.
106              
107             This is free software, licensed under:
108              
109             The MIT License
110              
111             =cut