File Coverage

blib/lib/Bitcoin/Crypto/Key/ExtPrivate.pm
Criterion Covered Total %
statement 87 87 100.0
branch 8 10 80.0
condition 8 13 61.5
subroutine 25 25 100.0
pod 7 7 100.0
total 135 142 95.0


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::ExtPrivate;
2             $Bitcoin::Crypto::Key::ExtPrivate::VERSION = '1.008_01'; # TRIAL
3             $Bitcoin::Crypto::Key::ExtPrivate::VERSION = '1.00801';
4 7     7   74416 use v5.10;
  7         73  
5 7     7   50 use strict;
  7         18  
  7         153  
6 7     7   38 use warnings;
  7         15  
  7         182  
7 7     7   1191 use Moo;
  7         15385  
  7         63  
8 7     7   8970 use Crypt::Mac::HMAC qw(hmac);
  7         13499  
  7         444  
9 7     7   3151 use Bitcoin::BIP39 qw(gen_bip39_mnemonic bip39_mnemonic_to_entropy entropy_to_bip39_mnemonic);
  7         9794  
  7         451  
10              
11 7     7   2639 use Bitcoin::Crypto::BIP44;
  7         38  
  7         306  
12 7     7   4003 use Bitcoin::Crypto::Key::ExtPublic;
  7         45  
  7         320  
13 7     7   67 use Bitcoin::Crypto::Config;
  7         135  
  7         240  
14 7     7   138 use Bitcoin::Crypto::Helpers qw(new_bigint pad_hex ensure_length verify_bytestring);
  7         25  
  7         605  
15 7     7   52 use Bitcoin::Crypto::Util qw(mnemonic_to_seed);
  7         21  
  7         342  
16 7     7   51 use Bitcoin::Crypto::Exception;
  7         24  
  7         239  
17              
18 7     7   47 use namespace::clean;
  7         16  
  7         68  
19              
20             with qw(Bitcoin::Crypto::Role::ExtendedKey);
21              
22 1082     1082   7465 sub _is_private { 1 }
23              
24             sub generate_mnemonic
25             {
26 9     9 1 2955 my ($class, $len, $lang) = @_;
27 9         33 my ($min_len, $len_div, $max_len) = (128, 32, 256);
28 9   66     59 $len //= $min_len;
29 9   100     41 $lang //= 'en';
30              
31             # bip39 specification values
32 9 100 33     116 Bitcoin::Crypto::Exception::MnemonicGenerate->raise(
      66        
33             "required entropy of between $min_len and $max_len bits, divisible by $len_div"
34             ) if $len < $min_len || $len > $max_len || $len % $len_div != 0;
35              
36             return Bitcoin::Crypto::Exception::MnemonicGenerate->trap_into(
37             sub {
38 8     8   49 my $ret = gen_bip39_mnemonic(bits => $len, language => $lang);
39 8         102659 $ret->{mnemonic};
40             }
41 8         99 );
42             }
43              
44             sub mnemonic_from_entropy
45             {
46 6     6 1 439 my ($class, $entropy, $lang) = @_;
47 6   50     22 $lang //= 'en';
48              
49             return Bitcoin::Crypto::Exception::MnemonicGenerate->trap_into(
50             sub {
51 6     6   30 entropy_to_bip39_mnemonic(
52             entropy => $entropy,
53             language => $lang
54             );
55             }
56 6         46 );
57             }
58              
59             sub from_mnemonic
60             {
61 30     30 1 12426 my ($class, $mnemonic, $password, $lang) = @_;
62              
63 30 100       133 if (defined $lang) {
64              
65             # checks validity of seed in given language
66             # requires Wordlist::LANG::BIP39 module for given LANG
67             Bitcoin::Crypto::Exception::MnemonicCheck->trap_into(
68             sub {
69 16     16   80 bip39_mnemonic_to_entropy(
70             mnemonic => $mnemonic,
71             language => $lang
72             );
73             }
74 16         123 );
75             }
76              
77 30         195 return $class->from_seed(mnemonic_to_seed($mnemonic, $password));
78             }
79              
80             sub from_seed
81             {
82 43     43 1 205 my ($class, $seed) = @_;
83 43         226 verify_bytestring($seed);
84              
85 43         495 my $bytes = hmac('SHA512', 'Bitcoin seed', $seed);
86 43         149 my $key = substr $bytes, 0, 32;
87 43         197 my $cc = substr $bytes, 32, 32;
88              
89 43         1517 return $class->new(
90             key_instance => $key,
91             chain_code => $cc,
92             );
93             }
94              
95             sub from_hex_seed
96             {
97 9     9 1 75 my ($class, $seed) = @_;
98              
99 9         50 return $class->from_seed(pack 'H*', pad_hex $seed);
100             }
101              
102             sub get_public_key
103             {
104 64     64 1 14122 my ($self) = @_;
105              
106 64         218 my $public = Bitcoin::Crypto::Key::ExtPublic->new(
107             key_instance => $self->raw_key('public'),
108             chain_code => $self->chain_code,
109             child_number => $self->child_number,
110             parent_fingerprint => $self->parent_fingerprint,
111             depth => $self->depth,
112             network => $self->network,
113             purpose => $self->purpose,
114             );
115              
116 64         342 return $public;
117             }
118              
119             sub derive_key_bip44
120             {
121 23     23 1 31491 my ($self, %data) = @_;
122 23         581 my $path = Bitcoin::Crypto::BIP44->new(
123             %data,
124             coin_type => $self,
125             );
126              
127 23         2887 return $self->derive_key($path);
128             }
129              
130             sub _derive_key_partial
131             {
132 261     261   667 my ($self, $child_num, $hardened) = @_;
133              
134 261         450 my $hmac_data;
135 261 100       564 if ($hardened) {
136              
137             # zero byte
138 99         216 $hmac_data .= "\x00";
139              
140             # key data - 32 bytes
141 99         295 $hmac_data .= ensure_length $self->raw_key, Bitcoin::Crypto::Config::key_max_length;
142             }
143             else {
144             # public key data - SEC compressed form
145 162         445 $hmac_data .= $self->raw_key('public_compressed');
146             }
147              
148             # child number - 4 bytes
149 261         1336 $hmac_data .= ensure_length pack('N', $child_num), 4;
150              
151 261         3097 my $data = hmac('SHA512', $self->chain_code, $hmac_data);
152 261         700 my $chain_code = substr $data, 32, 32;
153              
154 261         1020 my $number = new_bigint(substr $data, 0, 32);
155 261         61109 my $key_num = new_bigint($self->raw_key);
156 261         52983 my $n_order = new_bigint(pack 'H*', $self->key_instance->curve2hash->{order});
157              
158 261 50       52316 Bitcoin::Crypto::Exception::KeyDerive->raise(
159             "key $child_num in sequence was found invalid"
160             ) if $number->bge($n_order);
161              
162 261         8648 $number->badd($key_num);
163 261         17391 $number->bmod($n_order);
164              
165 261 50       21261 Bitcoin::Crypto::Exception::KeyDerive->raise(
166             "key $child_num in sequence was found invalid"
167             ) if $number->beq(0);
168              
169 261         49680 return $self->new(
170             key_instance => $number->as_bytes,
171             chain_code => $chain_code,
172             child_number => $child_num,
173             parent_fingerprint => $self->get_fingerprint,
174             depth => $self->depth + 1,
175             );
176             }
177              
178             1;
179              
180             __END__
181             =head1 NAME
182              
183             Bitcoin::Crypto::Key::ExtPrivate - Bitcoin extended private keys
184              
185             =head1 SYNOPSIS
186              
187             use Bitcoin::Crypto::Key::ExtPrivate;
188              
189             # generate mnemonic words first
190             my $mnemonic = Bitcoin::Crypto::Key::ExtPrivate->generate_mnemonic;
191             print "Your mnemonic is: $mnemonic";
192              
193             # create ExtPrivateKey from mnemonic (without password)
194             my $key = Bitcoin::Crypto::Key::ExtPrivate->from_mnemonic($mnemonic);
195             my $ser_key = $key->to_serialized_base58;
196             print "Your exported master key is: $ser_key";
197              
198             # derive child private key
199             my $path = "m/0'";
200             my $child_key = $key->derive_key($path);
201             my $ser_child_key = $child_key->to_serialized_base58;
202             print "Your exported $path child key is: $ser_child_key";
203              
204             # create basic keypair
205             my $basic_private = $child_key->get_basic_key;
206             my $basic_public = $child_key->get_public_key->get_basic_key;
207              
208             =head1 DESCRIPTION
209              
210             This class allows you to create an extended private key instance.
211              
212             You can use an extended private key to:
213              
214             =over 2
215              
216             =item * generate extended public keys
217              
218             =item * derive extended keys using a path
219              
220             =item * restore keys from mnemonic codes, seeds and base58 format
221              
222             =back
223              
224             see L<Bitcoin::Crypto::Network> if you want to work with other networks than Bitcoin Mainnet.
225              
226             =head1 METHODS
227              
228             =head2 new
229              
230             Constructor is reserved for internal and advanced use only. Use
231             L</from_mnemonic>, L</from_seed>, L</from_hex_seed>, L</from_serialized> and
232             L</from_serialized_base58> instead.
233              
234             =head2 generate_mnemonic
235              
236             $mnemonic = $class->generate_mnemonic($len = 128, $lang = 'en')
237              
238             Generates a new mnemonic code using L<Bytes::Random::Secure>. Default entropy is 128 bits.
239             With C<$len> this can be changed to up to 256 bits with 32 bit step.
240              
241             Other languages than english require additional modules for L<Bitcoin::BIP39>.
242              
243             Returns newly generated BIP39 mnemonic string.
244             Dies when C<$len> is invalid (under 128, above 256 or not divisible by 32).
245              
246             In some environments a problem may be encountered that causes the secure random bytes generator to block the program execution (See L<Bytes::Random::Secure/"BLOCKING ENTROPY SOURCE">). In this case you can use I<mnemonic_from_entropy> and pass in entropy generated by L<Bytes::Random::Secure> in non-blocking mode (via the OO interface).
247              
248             =head2 mnemonic_from_entropy
249              
250             $mnemonic = $class->mnemonic_from_entropy($bytes, $lang = 'en')
251              
252             Generates a new mnemonic code from custom entropy given in C<$bytes> (a bytestring). This entropy should be of the same bit size as in L</"generate_mnemonic">. Returns newly generated BIP39 mnemonic string.
253              
254             This can be useful to avoid relying on the underlying implementation of L<Bitcoin::BIP39>.
255              
256             Another use would be implementing one's own entropy source that can be truly random, not just cryptographically-secure. A popular example would be capturing user's mouse movements.
257              
258             Be aware that the method you use to generate a mnemonic will be a very important factor in your key's security. If possible, use real sources of randomness (not pseudo-random) or a cryptographically secure pseduo-random number generator like the one used by L<Bytes::Random::Secure>.
259              
260             =head2 from_mnemonic
261              
262             $key_object = $class->from_mnemonic($mnemonic, $password = '', $lang = undef)
263              
264             Creates a new key from given mnemonic and password.
265              
266             Note that technically any password is correct and there's no way to tell if it was mistaken.
267              
268             If you need to validate if C<$mnemonic> is a valid mnemonic you should specify C<$lang>, e.g. 'en'.
269              
270             If no C<$lang> is given then any string passed as C<$mnemonic> will produce a valid key.
271              
272             Returns a new instance of this class.
273              
274             B<Important note about unicode:> this function only accepts UTF8-decoded strings (both C<$mnemonic> and C<$password>), but can't detect whether it got it or not. This will only become a problem if you use non-ascii mnemonic and/or password. If there's a possibility of non-ascii, always use utf8 and set binmodes to get decoded (wide) characters to avoid problems recovering your wallet.
275              
276             =head2 from_seed
277              
278             $key_object = $class->from_seed($seed)
279              
280             Creates and returns a new key from seed, which can be any data of any length. C<$seed> is expected to be a byte string.
281              
282             =head2 from_hex_seed
283              
284             $key_object = $class->from_hex_seed($seed)
285              
286             Same as C<from_seed>, but C<$seed> is treated as hex string.
287              
288             =head2 to_serialized
289              
290             $serialized = $object->to_serialized()
291              
292             Returns the key serialized in format specified in BIP32 as byte string.
293              
294             =head2 to_serialized_base58
295              
296             $serialized_base58 = $object->to_serialized_base58()
297              
298             Behaves the same as C<to_serialized>, but performs Base58Check encoding on the resulting byte string.
299              
300             =head2 from_serialized
301              
302             $key_object = $class->from_serialized($serialized, $network = undef)
303              
304             Tries to unserialize byte string C<$serialized> with format specified in BIP32.
305              
306             Dies on errors. If multiple networks match serialized data specify C<$network> manually (id of the network) to avoid exception.
307              
308             =head2 from_serialized_base58
309              
310             $key_object = $class->from_serialized_base58($base58, $network = undef)
311              
312             Same as C<from_serialized>, but performs Base58Check decoding on C<$base58> argument.
313              
314             =head2 set_network
315              
316             $key_object = $object->set_network($val)
317              
318             Change key's network state to C<$val>. It can be either network name present in L<Bitcoin::Crypto::Network> package or an instance of this class.
319              
320             Returns current key instance.
321              
322             =head2 get_public_key
323              
324             $public_key_object = $object->get_public_key()
325              
326             Returns instance of L<Bitcoin::Crypto::Key::ExtPublic> generated from the private key.
327              
328             =head2 get_basic_key
329              
330             $basic_key_object = $object->get_basic_key()
331              
332             Returns the key in basic format: L<Bitcoin::Crypto::Key::Private>
333              
334             =head2 derive_key
335              
336             $derived_key_object = $object->derive_key($path)
337              
338             Performs extended key derivation as specified in BIP32 on the current key with C<$path>. Dies on error.
339              
340             See BIP32 document for details on derivation paths and methods.
341              
342             Returns a new extended key instance - result of a derivation.
343              
344             =head2 derive_key_bip44
345              
346             $derived_key_object = $object->derive_key_bip44(%data)
347              
348             A helper that constructs a L<Bitcoin::Crypto::BIP44> path from C<%data> and calls L</derive_key> with it. Refer to L<Bitcoin::Crypto::BIP44/PROPERTIES> to see what you can include in C<%data>.
349              
350             Using this method instead of specifying BIP44 path yourself will make sure all features of BIP44 derivation will be enabled, like different prefixes for extended keys (C<xprv> / C<yprv> / C<zprv>) and address type generation checking.
351              
352             I<Note: coin_type parameter will be ignored, and the current network configuration set in the extended key will be used.>
353              
354             =head2 get_fingerprint
355              
356             $fingerprint = $object->get_fingerprint($len = 4)
357              
358             Returns a fingerprint of the extended key of C<$len> length (byte string)
359              
360             =head1 EXCEPTIONS
361              
362             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:
363              
364             =over 2
365              
366             =item * MnemonicGenerate - mnemonic couldn't be generated correctly
367              
368             =item * MnemonicCheck - mnemonic didn't pass the validity check
369              
370             =item * KeyDerive - key couldn't be derived correctly
371              
372             =item * KeyCreate - key couldn't be created correctly
373              
374             =item * NetworkConfig - incomplete or corrupted network configuration
375              
376             =back
377              
378             =head1 SEE ALSO
379              
380             =over 2
381              
382             =item L<Bitcoin::Crypto::Key::ExtPublic>
383              
384             =item L<Bitcoin::Crypto::Network>
385              
386             =back
387              
388             =cut
389