File Coverage

lib/Crypt/Perl/ECDSA/Deterministic.pm
Criterion Covered Total %
statement 57 59 96.6
branch 10 12 83.3
condition 2 3 66.6
subroutine 10 10 100.0
pod 0 4 0.0
total 79 88 89.7


line stmt bran cond sub pod time code
1             package Crypt::Perl::ECDSA::Deterministic;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Crypt::Perl::ECDSA::Deterministic
8              
9             =head1 DISCUSSION
10              
11             This module implements L’s
12             algorithm for deterministic ECDSA signatures.
13              
14             =cut
15              
16 4     4   491 use strict;
  4         10  
  4         161  
17 4     4   23 use warnings;
  4         9  
  4         157  
18              
19 4     4   24 use Digest::SHA ();
  4         8  
  4         64  
20              
21 4     4   18 use Crypt::Perl::BigInt ();
  4         9  
  4         67  
22 4     4   541 use Crypt::Perl::Math ();
  4         20  
  4         3077  
23              
24             our $q;
25             our $qlen;
26             our $qlen_bytelen;
27              
28             sub generate_k {
29              
30             # $h1 = the message’s hash, as per $hashfunc
31 375     375 0 176443 my ($order, $key, $h1, $hashfn) = @_;
32              
33 375 50       5396 my $hmac_cr = Digest::SHA->can("hmac_$hashfn") or do {
34 0         0 die "Unknown deterministic ECDSA hashing algorithm: $hashfn";
35             };
36              
37 375         2415 local $q = $order;
38 375         4155 local $qlen = length $order->to_bin();
39 375         15454 local $qlen_bytelen = Crypt::Perl::Math::ceil( $qlen / 8 );
40              
41 375         1749 my $privkey_bytes = $key->as_bytes();
42 375         2808 substr( $privkey_bytes, 0, 0, "\0" x ($qlen_bytelen - length $privkey_bytes) );
43              
44             # printf "h1: %v.02x\n", $h1;
45             # printf "x: %v.02x\n", $privkey_bytes;
46              
47             # printf "bits2octets(h1): %v.02x\n", bits2octets($h1);
48              
49 375         2002 my $hashlen = length $h1;
50              
51 375         1950 my $V = "\x01" x $hashlen;
52              
53 375         1321 my $K = "\x00" x $hashlen;
54              
55 375         2919 $K = $hmac_cr->(
56             $V . "\0" . $privkey_bytes . bits2octets($h1),
57             $K,
58             );
59             # printf "K after step d: %v.02x\n", $K;
60              
61 375         3224 $V = $hmac_cr->( $V, $K );
62             # printf "V after step E: %v.02x\n", $V;
63              
64 375         2705 $K = $hmac_cr->(
65             $V . "\1" . $privkey_bytes . bits2octets($h1),
66             $K,
67             );
68             # printf "K after step F: %v.02x\n", $K;
69              
70 375         3740 $V = $hmac_cr->( $V, $K );
71             # printf "V after step G: %v.02x\n", $V;
72              
73 375         1126 my $k;
74              
75 375         747 while (1) {
76 521         2144 my $T = q<>;
77              
78 521         1329 while (1) {
79 1035         6889 $V = $hmac_cr->( $V, $K );
80 1035         2261 $T .= $V;
81              
82 1035 100       2129 last if length(_bytes_to_bitstxt($T)) >= $qlen;
83             }
84             # printf "new T: %v.02x\n", $T;
85             # print Crypt::Perl::BigInt->from_bytes($T)->to_bin() . $/;
86              
87 521         1728 $k = bits2int($T, $qlen);
88              
89 521 100 66     133263 if ($k->bge(1) && $k->blt($order)) {
90             # print "got good k\n";
91             # TODO: determine $r’s suitability
92 375         61709 last;
93             }
94              
95             # printf "bad k: %v.02x\n", $k->to_bytes();
96              
97 146         24178 $K = $hmac_cr->( $V . "\0", $K );
98             # printf "new K: %v.02x\n", $K;
99 146         1357 $V = $hmac_cr->( $V, $K );
100             # printf "new V: %v.02x\n", $V;
101             }
102              
103 375         1908 return $k;
104             }
105              
106             sub _bytes_to_bitstxt {
107 2306     2306   9382 unpack 'B*', $_[0];
108             }
109              
110             sub bits2int {
111 1271     1271 0 3524 my ($bits, $qlen) = @_;
112              
113 1271         2618 my $blen = 8 * length $bits;
114 1271         3039 $bits = _bytes_to_bitstxt($bits);
115              
116 1271 100       3811 if ($qlen < $blen) {
117 591         1669 substr($bits, -($blen - $qlen)) = q<>;
118             }
119              
120 1271         4889 return Crypt::Perl::BigInt->from_bin($bits);
121             }
122              
123             sub int2octets {
124 750     750 0 2850 my $octets = shift()->as_bytes();
125              
126 750 50       5043 if (length($octets) > $qlen_bytelen) {
    100          
127 0         0 substr( $octets, 0, -$qlen_bytelen ) = q<>;
128             }
129             elsif (length($octets) < $qlen_bytelen) {
130 600         4133 substr( $octets, 0, 0, "\0" x ($qlen_bytelen - length $octets) );
131             }
132              
133 750         12716 return $octets;
134             }
135              
136             sub bits2octets {
137 750     750 0 2346 my ($bits) = @_;
138 750         3026 my $z1 = bits2int($bits, $qlen);
139              
140 750         196185 my $z2 = $z1->copy()->bmod($q);
141              
142 750         76473 return int2octets($z2, $qlen);
143             }
144              
145             1;