line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Bitcoin::Crypto::BIP44; |
2
|
|
|
|
|
|
|
$Bitcoin::Crypto::BIP44::VERSION = '1.008'; |
3
|
7
|
|
|
7
|
|
865
|
use v5.10; |
|
7
|
|
|
|
|
27
|
|
4
|
7
|
|
|
7
|
|
47
|
use strict; |
|
7
|
|
|
|
|
20
|
|
|
7
|
|
|
|
|
163
|
|
5
|
7
|
|
|
7
|
|
39
|
use warnings; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
222
|
|
6
|
7
|
|
|
7
|
|
49
|
use Moo; |
|
7
|
|
|
|
|
15
|
|
|
7
|
|
|
|
|
58
|
|
7
|
7
|
|
|
7
|
|
4234
|
use Types::Standard qw(Enum Bool); |
|
7
|
|
|
|
|
235275
|
|
|
7
|
|
|
|
|
83
|
|
8
|
7
|
|
|
7
|
|
17869
|
use Types::Common::Numeric qw(PositiveOrZeroInt); |
|
7
|
|
|
|
|
118931
|
|
|
7
|
|
|
|
|
68
|
|
9
|
7
|
|
|
7
|
|
6327
|
use Scalar::Util qw(blessed); |
|
7
|
|
|
|
|
23
|
|
|
7
|
|
|
|
|
414
|
|
10
|
|
|
|
|
|
|
|
11
|
7
|
|
|
7
|
|
2227
|
use Bitcoin::Crypto::Types qw(BIP44Purpose); |
|
7
|
|
|
|
|
26
|
|
|
7
|
|
|
|
|
89
|
|
12
|
7
|
|
|
7
|
|
4982
|
use Bitcoin::Crypto::Network; |
|
7
|
|
|
|
|
24
|
|
|
7
|
|
|
|
|
238
|
|
13
|
7
|
|
|
7
|
|
42
|
use Bitcoin::Crypto::Exception; |
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
599
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub _get_network_constant |
16
|
|
|
|
|
|
|
{ |
17
|
|
|
|
|
|
|
my ($network) = @_; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $coin_type = $network->bip44_coin; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
Bitcoin::Crypto::Exception::NetworkConfig->raise( |
22
|
|
|
|
|
|
|
"no bip44_coin constant found in network configuration" |
23
|
|
|
|
|
|
|
) unless defined $coin_type; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
return $coin_type; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
7
|
|
|
7
|
|
52
|
use namespace::clean; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
62
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has 'purpose' => ( |
31
|
|
|
|
|
|
|
is => 'ro', |
32
|
|
|
|
|
|
|
isa => BIP44Purpose, |
33
|
|
|
|
|
|
|
default => sub { 44 }, |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has 'coin_type' => ( |
37
|
|
|
|
|
|
|
is => 'ro', |
38
|
|
|
|
|
|
|
isa => PositiveOrZeroInt, |
39
|
|
|
|
|
|
|
coerce => sub { |
40
|
|
|
|
|
|
|
my ($coin_type) = @_; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
if (blessed $coin_type) { |
43
|
|
|
|
|
|
|
$coin_type = $coin_type->network |
44
|
|
|
|
|
|
|
if $coin_type->DOES('Bitcoin::Crypto::Role::Network'); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
$coin_type = _get_network_constant($coin_type) |
47
|
|
|
|
|
|
|
if $coin_type->isa('Bitcoin::Crypto::Network'); |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
return $coin_type; |
51
|
|
|
|
|
|
|
}, |
52
|
|
|
|
|
|
|
default => sub { |
53
|
|
|
|
|
|
|
_get_network_constant(Bitcoin::Crypto::Network->get); |
54
|
|
|
|
|
|
|
}, |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
has 'account' => ( |
58
|
|
|
|
|
|
|
is => 'ro', |
59
|
|
|
|
|
|
|
isa => PositiveOrZeroInt, |
60
|
|
|
|
|
|
|
default => sub { 0 }, |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
has 'change' => ( |
64
|
|
|
|
|
|
|
is => 'ro', |
65
|
|
|
|
|
|
|
isa => Enum [1, 0], |
66
|
|
|
|
|
|
|
default => sub { 0 }, |
67
|
|
|
|
|
|
|
); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
has 'index' => ( |
70
|
|
|
|
|
|
|
is => 'ro', |
71
|
|
|
|
|
|
|
isa => PositiveOrZeroInt, |
72
|
|
|
|
|
|
|
default => sub { 0 }, |
73
|
|
|
|
|
|
|
); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
has 'get_account' => ( |
76
|
|
|
|
|
|
|
is => 'ro', |
77
|
|
|
|
|
|
|
isa => Bool, |
78
|
|
|
|
|
|
|
default => sub { 0 }, |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
has 'get_from_account' => ( |
82
|
|
|
|
|
|
|
is => 'ro', |
83
|
|
|
|
|
|
|
isa => Bool, |
84
|
|
|
|
|
|
|
default => sub { 0 }, |
85
|
|
|
|
|
|
|
); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
use overload |
88
|
7
|
|
|
|
|
57
|
q{""} => "as_string", |
89
|
7
|
|
|
7
|
|
4426
|
fallback => 1; |
|
7
|
|
|
|
|
20
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub as_string |
92
|
|
|
|
|
|
|
{ |
93
|
28
|
|
|
28
|
1
|
172
|
my ($self) = @_; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki |
96
|
|
|
|
|
|
|
# m / purpose' / coin_type' / account' / change / address_index |
97
|
|
|
|
|
|
|
|
98
|
28
|
|
|
|
|
253
|
my $path = sprintf "m/%u'/%u'/%u'", |
99
|
|
|
|
|
|
|
$self->purpose, $self->coin_type, $self->account; |
100
|
|
|
|
|
|
|
|
101
|
28
|
100
|
|
|
|
170
|
return $path |
102
|
|
|
|
|
|
|
if $self->get_account; |
103
|
|
|
|
|
|
|
|
104
|
19
|
100
|
|
|
|
63
|
$path = 'm' |
105
|
|
|
|
|
|
|
if $self->get_from_account; |
106
|
|
|
|
|
|
|
|
107
|
19
|
|
|
|
|
208
|
return sprintf "%s/%u/%u", |
108
|
|
|
|
|
|
|
$path, $self->change, $self->index; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
1; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
__END__ |
114
|
|
|
|
|
|
|
=head1 NAME |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
Bitcoin::Crypto::BIP44 - BIP44 implementation in Perl |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head1 SYNOPSIS |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
use Bitcoin::Crypto::BIP44; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
my $path = Bitcoin::Crypto::BIP44->new( |
123
|
|
|
|
|
|
|
coin_type => Bitcoin::Crypto::Network->get('bitcoin_testnet'), # can also be a number or a key instance |
124
|
|
|
|
|
|
|
index => 43, |
125
|
|
|
|
|
|
|
# account => 0, |
126
|
|
|
|
|
|
|
# change => 0, |
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# stringifies automatically |
130
|
|
|
|
|
|
|
say "$path"; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# can be used in key derivation |
133
|
|
|
|
|
|
|
$ext_private_key->derive_key($path); |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=head1 DESCRIPTION |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
This class is a helper for constructing BIP44-compilant key derivation paths. BIP44 describes the mechanism the HD (Hierarchical Deterministic) wallets use to decide derivation paths for coins. BIP49 and BIP84 are constructed the same way, but used for compat and segwit addresses respectively. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Each coin has its own C<coin_type> constant, a list of which is maintained here: L<https://github.com/satoshilabs/slips/blob/master/slip-0044.md>. L<Bitcoin::Crypto::Network> instances hold these constants under the C<bip44_coin> property. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
BIP44 objects stringify automatically and can be directly used in L<Bitcoin::Crypto::Key::ExtPrivate/derive_key> method. In return, any key object can be used as C<coin_type> in L</new>, which will automatically fetch coin_type number from the key's current network. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 PROPERTIES |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Refer to L<https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki> for details of those properties. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
All of these properties can be fetched using a method with the same name. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head2 purpose |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Purpose contains the BIP document number that you wish to use. Can be either C<44>, C<49> or C<84>. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
By default, number C<44> will be used. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head2 coin_type |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Needs to be a non-negative integer number. It should be less than C<2^31> (but will not check for that). |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Will also accept key objects and network objects, as it is possible to fetch the constant for them. In this case, it might raise an exception if the network does not contain the C<bip44_coin> constant. |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
This value should be in line with the table of BIP44 constants mentioned above. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
By default, the value defined in the current default network will be used: see L<Bitcoin::Crypto::Network>. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 account |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Needs to be a non-negative integer number. It should be less than C<2^31> (but will not check for that). |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
By default, the value C<0> is used. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 change |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Needs to be a number C<1> (for addresses to be used as change outputs) or C<0> (for addresses that are to be used only internally). |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
By default, the value C<0> is used. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head2 index |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Needs to be a non-negative integer number. It should be less than C<2^31> (but will not check for that). |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
By default, the value C<0> is used. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head2 get_account |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
If passed C<1>, the resulting derivation path will only go as far as to the account part. L</index> and L</change> values will be ignored. Use this to get extended key for the account. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
By default, you will get the full derivation path. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head2 get_from_account |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
If passed C<1>, the resulting derivation path will start after the account part. L</purpose>, L</coin_type> and L</account> values will be ignored. Use this to further derive key that was only derived up to the account part. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
By default, you will get the full derivation path. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head1 METHODS |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head2 new |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
$key_object = $class->new(%data) |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
This is a regular Moo constructor, which can be used to create the object. It takes arguments specified in L</PROPERTIES>. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Returns class instance. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head2 as_string |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
$path = $object->as_string() |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Stringifies the object as BIP44-compilant key derivation path. Can be used indirectly by just stringifying the object. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 EXCEPTIONS |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
This module throws an instance of L<Bitcoin::Crypto::Exception> if it encounters an error. It can produce the following error types from the L<Bitcoin::Crypto::Exception> namespace: |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=over 2 |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item * NetworkConfig - incomplete or corrupted network configuration |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=back |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 SEE ALSO |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=over 2 |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item L<Bitcoin::Crypto::Key::ExtPrivate> |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item L<Bitcoin::Crypto::Network> |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=back |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|