File Coverage

blib/lib/Bitcoin/Crypto/Key/ExtPrivate.pm
Criterion Covered Total %
statement 92 92 100.0
branch 8 10 80.0
condition 8 13 61.5
subroutine 26 26 100.0
pod 7 7 100.0
total 141 148 95.2


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::ExtPrivate;
2             $Bitcoin::Crypto::Key::ExtPrivate::VERSION = '1.008';
3 7     7   73633 use v5.10;
  7         46  
4 7     7   38 use strict;
  7         15  
  7         155  
5 7     7   35 use warnings;
  7         15  
  7         186  
6 7     7   1159 use Moo;
  7         14921  
  7         53  
7 7     7   8422 use Crypt::Mac::HMAC qw(hmac);
  7         14777  
  7         456  
8 7     7   3140 use Bitcoin::BIP39 qw(gen_bip39_mnemonic bip39_mnemonic_to_entropy entropy_to_bip39_mnemonic);
  7         9534  
  7         479  
9 7     7   51 use Scalar::Util qw(blessed);
  7         17  
  7         341  
10              
11 7     7   2576 use Bitcoin::Crypto::BIP44;
  7         36  
  7         334  
12 7     7   3195 use Bitcoin::Crypto::Key::ExtPublic;
  7         31  
  7         230  
13 7     7   53 use Bitcoin::Crypto::Config;
  7         15  
  7         198  
14 7     7   40 use Bitcoin::Crypto::Helpers qw(new_bigint pad_hex ensure_length verify_bytestring);
  7         18  
  7         467  
15 7     7   51 use Bitcoin::Crypto::Util qw(mnemonic_to_seed);
  7         27  
  7         286  
16 7     7   46 use Bitcoin::Crypto::Exception;
  7         22  
  7         158  
17              
18 7     7   36 use namespace::clean;
  7         17  
  7         46  
19              
20             with "Bitcoin::Crypto::Role::ExtendedKey";
21              
22 1082     1082   3308 sub _is_private { 1 }
23              
24             sub generate_mnemonic
25             {
26 9     9 1 4607 my ($class, $len, $lang) = @_;
27 9         31 my ($min_len, $len_div, $max_len) = (128, 32, 256);
28 9   66     47 $len //= $min_len;
29 9   100     42 $lang //= "en";
30              
31             # bip39 specification values
32 9 100 33     126 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   54 my $ret = gen_bip39_mnemonic(bits => $len, language => $lang);
39 8         101888 $ret->{mnemonic};
40             }
41 8         87 );
42             }
43              
44             sub mnemonic_from_entropy
45             {
46 6     6 1 567 my ($class, $entropy, $lang) = @_;
47 6   50     25 $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 16433 my ($class, $mnemonic, $password, $lang) = @_;
62              
63 30 100       122 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   84 bip39_mnemonic_to_entropy(
70             mnemonic => $mnemonic,
71             language => $lang
72             );
73             }
74 16         150 );
75             }
76              
77 30         196 return $class->from_seed(mnemonic_to_seed($mnemonic, $password));
78             }
79              
80             sub from_seed
81             {
82 43     43 1 193 my ($class, $seed) = @_;
83 43         226 verify_bytestring($seed);
84              
85 43         501 my $bytes = hmac("SHA512", "Bitcoin seed", $seed);
86 43         143 my $key = substr $bytes, 0, 32;
87 43         100 my $cc = substr $bytes, 32, 32;
88              
89 43         1115 return $class->new($key, $cc);
90             }
91              
92             sub from_hex_seed
93             {
94 9     9 1 324 my ($class, $seed) = @_;
95              
96 9         43 return $class->from_seed(pack "H*", pad_hex $seed);
97             }
98              
99             sub get_public_key
100             {
101 64     64 1 13704 my ($self) = @_;
102              
103 64         209 my $public = Bitcoin::Crypto::Key::ExtPublic->new(
104             $self->raw_key("public"),
105             $self->chain_code,
106             $self->child_number,
107             $self->parent_fingerprint,
108             $self->depth
109             );
110              
111 64         4076 $public->set_network($self->network);
112 64         345 $public->set_purpose($self->purpose);
113              
114 64         859 return $public;
115             }
116              
117             sub derive_key_bip44
118             {
119 23     23 1 29539 my ($self, %data) = @_;
120 23         533 my $path = Bitcoin::Crypto::BIP44->new(
121             %data,
122             coin_type => $self,
123             );
124              
125 23         850 return $self->derive_key($path);
126             }
127              
128             sub _derive_key_partial
129             {
130 261     261   697 my ($self, $child_num, $hardened) = @_;
131              
132 261         480 my $hmac_data;
133 261 100       651 if ($hardened) {
134              
135             # zero byte
136 99         235 $hmac_data .= "\x00";
137              
138             # key data - 32 bytes
139 99         328 $hmac_data .= ensure_length $self->raw_key, Bitcoin::Crypto::Config::key_max_length;
140             }
141             else {
142             # public key data - SEC compressed form
143 162         579 $hmac_data .= $self->raw_key("public_compressed");
144             }
145              
146             # child number - 4 bytes
147 261         1332 $hmac_data .= ensure_length pack("N", $child_num), 4;
148              
149 261         2992 my $data = hmac("SHA512", $self->chain_code, $hmac_data);
150 261         750 my $chain_code = substr $data, 32, 32;
151              
152 261         996 my $number = new_bigint(substr $data, 0, 32);
153 261         58362 my $key_num = new_bigint($self->raw_key);
154 261         52872 my $n_order = new_bigint(pack "H*", $self->key_instance->curve2hash->{order});
155              
156 261 50       51153 Bitcoin::Crypto::Exception::KeyDerive->raise(
157             "key $child_num in sequence was found invalid"
158             ) if $number->bge($n_order);
159              
160 261         7909 $number->badd($key_num);
161 261         17060 $number->bmod($n_order);
162              
163 261 50       20926 Bitcoin::Crypto::Exception::KeyDerive->raise(
164             "key $child_num in sequence was found invalid"
165             ) if $number->beq(0);
166              
167 261         47283 return (blessed $self)->new(
168             $number->as_bytes,
169             $chain_code,
170             $child_num,
171             $self->get_fingerprint,
172             $self->depth + 1
173             );
174             }
175              
176             1;
177              
178             __END__
179             =head1 NAME
180              
181             Bitcoin::Crypto::Key::ExtPrivate - Bitcoin extended private keys
182              
183             =head1 SYNOPSIS
184              
185             use Bitcoin::Crypto::Key::ExtPrivate;
186              
187             # generate mnemonic words first
188             my $mnemonic = Bitcoin::Crypto::Key::ExtPrivate->generate_mnemonic;
189             print "Your mnemonic is: $mnemonic";
190              
191             # create ExtPrivateKey from mnemonic (without password)
192             my $key = Bitcoin::Crypto::Key::ExtPrivate->from_mnemonic($mnemonic);
193             my $ser_key = $key->to_serialized_base58;
194             print "Your exported master key is: $ser_key";
195              
196             # derive child private key
197             my $path = "m/0'";
198             my $child_key = $key->derive_key($path);
199             my $ser_child_key = $child_key->to_serialized_base58;
200             print "Your exported $path child key is: $ser_child_key";
201              
202             # create basic keypair
203             my $basic_private = $child_key->get_basic_key;
204             my $basic_public = $child_key->get_public_key->get_basic_key;
205              
206             =head1 DESCRIPTION
207              
208             This class allows you to create an extended private key instance.
209              
210             You can use an extended private key to:
211              
212             =over 2
213              
214             =item * generate extended public keys
215              
216             =item * derive extended keys using a path
217              
218             =item * restore keys from mnemonic codes, seeds and base58 format
219              
220             =back
221              
222             see L<Bitcoin::Crypto::Network> if you want to work with other networks than Bitcoin Mainnet.
223              
224             =head1 METHODS
225              
226             =head2 generate_mnemonic
227              
228             $mnemonic = $class->generate_mnemonic($len = 128, $lang = "en")
229              
230             Generates a new mnemonic code using L<Bytes::Random::Secure>. Default entropy is 128 bits.
231             With C<$len> this can be changed to up to 256 bits with 32 bit step.
232              
233             Other languages than english require additional modules for L<Bitcoin::BIP39>.
234              
235             Returns newly generated BIP39 mnemonic string.
236             Dies when C<$len> is invalid (under 128, above 256 or not divisible by 32).
237              
238             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).
239              
240             =head2 mnemonic_from_entropy
241              
242             $mnemonic = $class->mnemonic_from_entropy($bytes, $lang = "en")
243              
244             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.
245              
246             This can be useful to avoid relying on the underlying implementation of L<Bitcoin::BIP39>.
247              
248             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.
249              
250             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>.
251              
252             =head2 from_mnemonic
253              
254             $key_object = $class->from_mnemonic($mnemonic, $password = "", $lang = undef)
255              
256             Creates a new key from given mnemonic and password.
257              
258             Note that technically any password is correct and there's no way to tell if it was mistaken.
259              
260             If you need to validate if C<$mnemonic> is a valid mnemonic you should specify C<$lang>, e.g. "en".
261              
262             If no C<$lang> is given then any string passed as C<$mnemonic> will produce a valid key.
263              
264             Returns a new instance of this class.
265              
266             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.
267              
268             =head2 from_seed
269              
270             $key_object = $class->from_seed($seed)
271              
272             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.
273              
274             =head2 from_hex_seed
275              
276             $key_object = $class->from_hex_seed($seed)
277              
278             Same as C<from_seed>, but C<$seed> is treated as hex string.
279              
280             =head2 to_serialized
281              
282             $serialized = $object->to_serialized()
283              
284             Returns the key serialized in format specified in BIP32 as byte string.
285              
286             =head2 to_serialized_base58
287              
288             $serialized_base58 = $object->to_serialized_base58()
289              
290             Behaves the same as C<to_serialized>, but performs Base58Check encoding on the resulting byte string.
291              
292             =head2 from_serialized
293              
294             $key_object = $class->from_serialized($serialized, $network = undef)
295              
296             Tries to unserialize byte string C<$serialized> with format specified in BIP32.
297              
298             Dies on errors. If multiple networks match serialized data specify C<$network> manually (id of the network) to avoid exception.
299              
300             =head2 from_serialized_base58
301              
302             $key_object = $class->from_serialized_base58($base58, $network = undef)
303              
304             Same as C<from_serialized>, but performs Base58Check decoding on C<$base58> argument.
305              
306             =head2 set_network
307              
308             $key_object = $object->set_network($val)
309              
310             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.
311              
312             Returns current key instance.
313              
314             =head2 get_public_key
315              
316             $public_key_object = $object->get_public_key()
317              
318             Returns instance of L<Bitcoin::Crypto::Key::ExtPublic> generated from the private key.
319              
320             =head2 get_basic_key
321              
322             $basic_key_object = $object->get_basic_key()
323              
324             Returns the key in basic format: L<Bitcoin::Crypto::Key::Private>
325              
326             =head2 derive_key
327              
328             $derived_key_object = $object->derive_key($path)
329              
330             Performs extended key derivation as specified in BIP32 on the current key with C<$path>. Dies on error.
331              
332             See BIP32 document for details on derivation paths and methods.
333              
334             Returns a new extended key instance - result of a derivation.
335              
336             =head2 derive_key_bip44
337              
338             $derived_key_object = $object->derive_key_bip44(%data)
339              
340             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>.
341              
342             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.
343              
344             I<Note: coin_type parameter will be ignored, and the current network configuration set in the extended key will be used.>
345              
346             =head2 get_fingerprint
347              
348             $fingerprint = $object->get_fingerprint($len = 4)
349              
350             Returns a fingerprint of the extended key of C<$len> length (byte string)
351              
352             =head1 EXCEPTIONS
353              
354             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:
355              
356             =over 2
357              
358             =item * MnemonicGenerate - mnemonic couldn't be generated correctly
359              
360             =item * MnemonicCheck - mnemonic didn't pass the validity check
361              
362             =item * KeyDerive - key couldn't be derived correctly
363              
364             =item * KeyCreate - key couldn't be created correctly
365              
366             =item * NetworkConfig - incomplete or corrupted network configuration
367              
368             =back
369              
370             =head1 SEE ALSO
371              
372             =over 2
373              
374             =item L<Bitcoin::Crypto::Key::ExtPublic>
375              
376             =item L<Bitcoin::Crypto::Network>
377              
378             =back
379              
380             =cut
381