line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Bitcoin::Crypto::Helpers; |
2
|
|
|
|
|
|
|
$Bitcoin::Crypto::Helpers::VERSION = '2.000_01'; # TRIAL |
3
|
|
|
|
|
|
|
$Bitcoin::Crypto::Helpers::VERSION = '2.00001'; |
4
|
36
|
|
|
36
|
|
151415
|
use v5.10; |
|
36
|
|
|
|
|
151
|
|
5
|
36
|
|
|
36
|
|
250
|
use strict; |
|
36
|
|
|
|
|
131
|
|
|
36
|
|
|
|
|
791
|
|
6
|
36
|
|
|
36
|
|
185
|
use warnings; |
|
36
|
|
|
|
|
94
|
|
|
36
|
|
|
|
|
1186
|
|
7
|
36
|
|
|
36
|
|
208
|
use Exporter qw(import); |
|
36
|
|
|
|
|
108
|
|
|
36
|
|
|
|
|
1476
|
|
8
|
36
|
|
|
36
|
|
230
|
use List::Util qw(max); |
|
36
|
|
|
|
|
80
|
|
|
36
|
|
|
|
|
4416
|
|
9
|
36
|
|
|
36
|
|
11843
|
use Crypt::PK::ECC; |
|
36
|
|
|
|
|
290094
|
|
|
36
|
|
|
|
|
1889
|
|
10
|
36
|
|
|
36
|
|
286
|
use Carp qw(carp); |
|
36
|
|
|
|
|
96
|
|
|
36
|
|
|
|
|
1686
|
|
11
|
|
|
|
|
|
|
|
12
|
36
|
|
|
36
|
|
8479
|
use Bitcoin::Crypto::Constants; |
|
36
|
|
|
|
|
84
|
|
|
36
|
|
|
|
|
1108
|
|
13
|
36
|
|
|
36
|
|
14768
|
use Bitcoin::Crypto::Exception; |
|
36
|
|
|
|
|
283
|
|
|
36
|
|
|
|
|
3645
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
BEGIN { |
16
|
36
|
|
|
36
|
|
54733
|
require Math::BigInt; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Version 1.6003 of optional GMP is required for the from_bytes / to_bytes implementations |
19
|
36
|
50
|
|
|
|
1304157
|
if (eval { require Math::BigInt::GMP; Math::BigInt::GMP->VERSION('1.6003'); 1 }) { |
|
36
|
|
|
|
|
6757
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
20
|
0
|
|
|
|
|
0
|
Math::BigInt->import(try => 'GMP,LTM'); |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
else { |
23
|
36
|
|
|
|
|
257
|
Math::BigInt->import(try => 'LTM'); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
28
|
|
|
|
|
|
|
pad_hex |
29
|
|
|
|
|
|
|
ensure_length |
30
|
|
|
|
|
|
|
add_ec_points |
31
|
|
|
|
|
|
|
pack_varint |
32
|
|
|
|
|
|
|
unpack_varint |
33
|
|
|
|
|
|
|
carp_once |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our @CARP_NOT; |
37
|
|
|
|
|
|
|
my %warned; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub carp_once |
40
|
|
|
|
|
|
|
{ |
41
|
21
|
|
|
21
|
0
|
57
|
my ($msg) = @_; |
42
|
|
|
|
|
|
|
|
43
|
21
|
100
|
|
|
|
91
|
return if $warned{$msg}; |
44
|
3
|
|
|
|
|
13
|
$warned{$msg} = 1; |
45
|
3
|
|
|
|
|
13
|
local @CARP_NOT = ((caller)[0]); |
46
|
3
|
|
|
|
|
124
|
carp($msg); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub pad_hex |
50
|
|
|
|
|
|
|
{ |
51
|
373
|
|
|
373
|
0
|
6653
|
my ($hex) = @_; |
52
|
373
|
|
|
|
|
909
|
$hex =~ s/\A0x//; |
53
|
373
|
|
|
|
|
895
|
$hex =~ tr/0-9a-fA-F//cd; |
54
|
373
|
|
|
|
|
2447
|
return '0' x (length($hex) % 2) . $hex; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub ensure_length |
58
|
|
|
|
|
|
|
{ |
59
|
1207
|
|
|
1207
|
0
|
5396
|
my ($packed, $bytelen) = @_; |
60
|
1207
|
|
|
|
|
2269
|
my $missing = $bytelen - length $packed; |
61
|
|
|
|
|
|
|
|
62
|
1207
|
100
|
|
|
|
2699
|
Bitcoin::Crypto::Exception->raise( |
63
|
|
|
|
|
|
|
"packed string exceeds maximum number of bytes allowed ($bytelen)" |
64
|
|
|
|
|
|
|
) if $missing < 0; |
65
|
|
|
|
|
|
|
|
66
|
1206
|
|
|
|
|
5399
|
return pack("x$missing") . $packed; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub pack_varint |
70
|
|
|
|
|
|
|
{ |
71
|
445
|
|
|
445
|
0
|
10447
|
my ($value) = @_; |
72
|
|
|
|
|
|
|
|
73
|
445
|
50
|
|
|
|
1039
|
Bitcoin::Crypto::Exception->raise( |
74
|
|
|
|
|
|
|
"VarInt must be positive or zero" |
75
|
|
|
|
|
|
|
) if $value < 0; |
76
|
|
|
|
|
|
|
|
77
|
445
|
100
|
|
|
|
1026
|
if ($value <= 0xfc) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
78
|
440
|
|
|
|
|
1571
|
return pack 'C', $value; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
elsif ($value <= 0xffff) { |
81
|
4
|
|
|
|
|
32
|
return "\xfd" . pack 'v', $value; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
elsif ($value <= 0xffffffff) { |
84
|
1
|
|
|
|
|
9
|
return "\xfe" . pack 'V', $value; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
else { |
87
|
|
|
|
|
|
|
# 32 bit archs should not reach this |
88
|
0
|
|
|
|
|
0
|
return "\xff" . (pack 'V', $value & 0xffffffff) . (pack 'V', $value >> 32); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub unpack_varint |
93
|
|
|
|
|
|
|
{ |
94
|
137
|
|
|
137
|
0
|
443
|
my ($stream) = @_; |
95
|
|
|
|
|
|
|
|
96
|
137
|
|
|
|
|
320
|
my $value = ord substr $stream, 0, 1, ''; |
97
|
137
|
|
|
|
|
226
|
my $length = 1; |
98
|
|
|
|
|
|
|
|
99
|
137
|
100
|
|
|
|
499
|
if ($value == 0xfd) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
100
|
2
|
50
|
|
|
|
10
|
Bitcoin::Crypto::Exception->raise( |
101
|
|
|
|
|
|
|
"cannot unpack VarInt: not enough data in stream" |
102
|
|
|
|
|
|
|
) if length $stream < 2; |
103
|
|
|
|
|
|
|
|
104
|
2
|
|
|
|
|
9
|
$value = unpack 'v', substr $stream, 0, 2; |
105
|
2
|
|
|
|
|
4
|
$length += 2; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
elsif ($value == 0xfe) { |
108
|
1
|
50
|
|
|
|
13
|
Bitcoin::Crypto::Exception->raise( |
109
|
|
|
|
|
|
|
"cannot unpack VarInt: not enough data in stream" |
110
|
|
|
|
|
|
|
) if length $stream < 4; |
111
|
|
|
|
|
|
|
|
112
|
1
|
|
|
|
|
8
|
$value = unpack 'V', substr $stream, 0, 4; |
113
|
1
|
|
|
|
|
2
|
$length += 4; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
elsif ($value == 0xff) { |
116
|
0
|
|
|
|
|
0
|
Bitcoin::Crypto::Exception->raise( |
117
|
|
|
|
|
|
|
"cannot unpack VarInt: no 64 bit support" |
118
|
|
|
|
|
|
|
) if !Bitcoin::Crypto::Constants::is_64bit; |
119
|
|
|
|
|
|
|
|
120
|
0
|
0
|
|
|
|
0
|
Bitcoin::Crypto::Exception->raise( |
121
|
|
|
|
|
|
|
"cannot unpack VarInt: not enough data in stream" |
122
|
|
|
|
|
|
|
) if length $stream < 8; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
0
|
my $lower = unpack 'V', substr $stream, 0, 4; |
125
|
0
|
|
|
|
|
0
|
my $higher = unpack 'V', substr $stream, 4, 4; |
126
|
0
|
|
|
|
|
0
|
$value = ($higher << 32) + $lower; |
127
|
0
|
|
|
|
|
0
|
$length += 8; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
137
|
|
|
|
|
470
|
return ($length, $value); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Self-contained implementation on elliptic curve points addition. |
134
|
|
|
|
|
|
|
# This is only a partial implementation, but should be good enough for key |
135
|
|
|
|
|
|
|
# derivation needs. Code borrowed from the archived Math::EllipticCurve::Prime |
136
|
|
|
|
|
|
|
# module. Returns undef for infinity points, expects to get a valid uncompressed |
137
|
|
|
|
|
|
|
# point data on input |
138
|
|
|
|
|
|
|
sub add_ec_points |
139
|
|
|
|
|
|
|
{ |
140
|
17
|
|
|
17
|
0
|
57
|
my ($point1, $point2) = @_; |
141
|
|
|
|
|
|
|
|
142
|
17
|
|
|
|
|
32
|
my $curve_size = Bitcoin::Crypto::Constants::key_max_length; |
143
|
17
|
|
|
|
|
67
|
my $curve_data = Crypt::PK::ECC->new->generate_key(Bitcoin::Crypto::Constants::curve_name)->curve2hash; |
144
|
17
|
|
|
|
|
51750
|
my $p = Math::BigInt->from_hex($curve_data->{prime}); |
145
|
17
|
|
|
|
|
3698
|
my $a = Math::BigInt->from_hex($curve_data->{A}); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
my $add_points = sub { |
148
|
17
|
|
|
17
|
|
63
|
my ($x1, $x2, $y1, $lambda) = @_; |
149
|
|
|
|
|
|
|
|
150
|
17
|
|
|
|
|
52
|
my $x = $lambda->copy->bmodpow(2, $p); |
151
|
17
|
|
|
|
|
3701
|
$x->bsub($x1); |
152
|
17
|
|
|
|
|
1506
|
$x->bsub($x2); |
153
|
17
|
|
|
|
|
1387
|
$x->bmod($p); |
154
|
|
|
|
|
|
|
|
155
|
17
|
|
|
|
|
1315
|
my $y = $x1->copy->bsub($x); |
156
|
17
|
|
|
|
|
1796
|
$y->bmul($lambda); |
157
|
17
|
|
|
|
|
871
|
$y->bsub($y1); |
158
|
17
|
|
|
|
|
1412
|
$y->bmod($p); |
159
|
|
|
|
|
|
|
|
160
|
17
|
|
|
|
|
1444
|
return {x => $x, y => $y}; |
161
|
17
|
|
|
|
|
2586
|
}; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
my $double = sub { |
164
|
0
|
|
|
0
|
|
0
|
my ($x, $y) = @_; |
165
|
0
|
|
|
|
|
0
|
my $lambda = $x->copy->bmodpow(2, $p); |
166
|
0
|
|
|
|
|
0
|
$lambda->bmul(3); |
167
|
0
|
|
|
|
|
0
|
$lambda->badd($a); |
168
|
0
|
|
|
|
|
0
|
my $bottom = $y->copy->bmul(2)->bmodinv($p); |
169
|
0
|
|
|
|
|
0
|
$lambda->bmul($bottom)->bmod($p); |
170
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
0
|
return $add_points->($x, $x, $y, $lambda); |
172
|
17
|
|
|
|
|
82
|
}; |
173
|
|
|
|
|
|
|
|
174
|
17
|
|
|
|
|
53
|
my $format = "(a$curve_size)*"; |
175
|
17
|
|
|
|
|
103
|
my ($px1, $py1) = map { Math::BigInt->from_bytes($_) } unpack $format, substr $point1, 1; |
|
34
|
|
|
|
|
1690
|
|
176
|
17
|
|
|
|
|
1600
|
my ($px2, $py2) = map { Math::BigInt->from_bytes($_) } unpack $format, substr $point2, 1; |
|
34
|
|
|
|
|
1488
|
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my $ret = sub { |
179
|
17
|
50
|
0
|
17
|
|
60
|
if ($px1->bcmp($px2)) { |
|
|
0
|
0
|
|
|
|
|
180
|
17
|
|
|
|
|
418
|
my $lambda = $py2->copy->bsub($py1); |
181
|
17
|
|
|
|
|
2193
|
my $bottom = $px2->copy->bsub($px1)->bmodinv($p); |
182
|
17
|
|
|
|
|
5698
|
$lambda->bmul($bottom)->bmod($p); |
183
|
|
|
|
|
|
|
|
184
|
17
|
|
|
|
|
2247
|
return $add_points->($px1, $px2, $py1, $lambda); |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
elsif ($py1->is_zero || $py2->is_zero || $py1->bcmp($py2)) { |
187
|
0
|
|
|
|
|
0
|
return undef; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
else { |
190
|
0
|
|
|
|
|
0
|
return $double->($px1, $py1); |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
} |
193
|
17
|
|
|
|
|
1616
|
->(); |
194
|
|
|
|
|
|
|
|
195
|
17
|
|
|
|
|
190
|
my $exp_x = $ret->{x}->to_bytes; |
196
|
17
|
|
|
|
|
546
|
my $exp_y = $ret->{y}->to_bytes; |
197
|
|
|
|
|
|
|
|
198
|
17
|
50
|
|
|
|
427
|
return defined $ret |
199
|
|
|
|
|
|
|
? "\x04" . |
200
|
|
|
|
|
|
|
ensure_length($exp_x, $curve_size) . |
201
|
|
|
|
|
|
|
ensure_length($exp_y, $curve_size) |
202
|
|
|
|
|
|
|
: undef; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# not exported - used exclusively by the internal FormatDesc type |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub parse_formatdesc |
208
|
|
|
|
|
|
|
{ |
209
|
246
|
|
|
246
|
0
|
184039
|
my ($type, $data) = @{$_[0]}; |
|
246
|
|
|
|
|
638
|
|
210
|
|
|
|
|
|
|
|
211
|
246
|
100
|
|
|
|
815
|
if ($type eq 'hex') { |
|
|
50
|
|
|
|
|
|
212
|
209
|
|
|
|
|
659
|
$data = pack 'H*', pad_hex $data; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
elsif ($type eq 'base58') { |
215
|
37
|
|
|
|
|
196
|
require Bitcoin::Crypto::Base58; |
216
|
37
|
|
|
|
|
160
|
$data = Bitcoin::Crypto::Base58::decode_base58check($data); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
244
|
|
|
|
|
1373
|
return $data; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
1; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Internal use only |
225
|
|
|
|
|
|
|
|