File Coverage

blib/lib/Bitcoin/Crypto/Key/ExtPublic.pm
Criterion Covered Total %
statement 42 42 100.0
branch 3 6 50.0
condition n/a
subroutine 11 11 100.0
pod n/a
total 56 59 94.9


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::ExtPublic;
2             $Bitcoin::Crypto::Key::ExtPublic::VERSION = '1.008_01'; # TRIAL
3             $Bitcoin::Crypto::Key::ExtPublic::VERSION = '1.00801';
4 8     8   70859 use v5.10;
  8         48  
5 8     8   64 use strict;
  8         20  
  8         214  
6 8     8   53 use warnings;
  8         18  
  8         275  
7 8     8   602 use Moo;
  8         7456  
  8         46  
8 8     8   5158 use Crypt::Mac::HMAC qw(hmac);
  8         3924  
  8         544  
9              
10 8     8   484 use Bitcoin::Crypto::Config;
  8         17  
  8         300  
11 8     8   1842 use Bitcoin::Crypto::Helpers qw(new_bigint ensure_length add_ec_points);
  8         30  
  8         602  
12 8     8   94 use Bitcoin::Crypto::Exception;
  8         20  
  8         278  
13              
14 8     8   61 use namespace::clean;
  8         24  
  8         97  
15              
16             with qw(Bitcoin::Crypto::Role::ExtendedKey);
17              
18 370     370   1916 sub _is_private { 0 }
19              
20             sub _derive_key_partial
21             {
22 15     15   56 my ($self, $child_num, $hardened) = @_;
23              
24 15 50       39 Bitcoin::Crypto::Exception::KeyDerive->raise(
25             'cannot derive hardened key from public key'
26             ) if $hardened;
27              
28             # public key data - SEC compressed form
29 15         54 my $hmac_data = $self->raw_key('public_compressed');
30              
31             # child number - 4 bytes
32 15         99 $hmac_data .= ensure_length pack('N', $child_num), 4;
33              
34 15         215 my $data = hmac('SHA512', $self->chain_code, $hmac_data);
35 15         41 my $chain_code = substr $data, 32, 32;
36              
37 15         59 my $n_order = new_bigint(pack 'H*', $self->key_instance->curve2hash->{order});
38 15         3609 my $number = new_bigint(substr $data, 0, 32);
39 15 50       3166 Bitcoin::Crypto::Exception::KeyDerive->raise(
40             "key $child_num in sequence was found invalid"
41             ) if $number->bge($n_order);
42              
43 15         603 my $key = $self->_create_key(substr $data, 0, 32);
44 15         174 my $point = $key->export_key_raw('public');
45 15         66 my $parent_point = $self->raw_key('public');
46 15         74 $point = add_ec_points($point, $parent_point);
47              
48 15 50       52 Bitcoin::Crypto::Exception::KeyDerive->raise(
49             "key $child_num in sequence was found invalid"
50             ) unless defined $point;
51              
52 15         65 return $self->new(
53             key_instance => $point,
54             chain_code => $chain_code,
55             child_number => $child_num,
56             parent_fingerprint => $self->get_fingerprint,
57             depth => $self->depth + 1,
58             );
59             }
60              
61             1;
62              
63             __END__
64             =head1 NAME
65              
66             Bitcoin::Crypto::Key::ExtPublic - Bitcoin extended public keys
67              
68             =head1 SYNOPSIS
69              
70             use Bitcoin::Crypto::Key::ExtPrivate;
71              
72             my $mnemonic = Bitcoin::Crypto::Key::ExtPrivate->generate_mnemonic;
73             my $key = Bitcoin::Crypto::Key::ExtPrivate->from_mnemonic($mnemonic);
74              
75             # derive child public key
76             my $path = "M/0";
77             my $child_key = $key->derive_key($path);
78             my $ser_child_key = $child_key->to_serialized_base58;
79             print "Your exported $path child key is: $ser_child_key";
80              
81             # create basic public key
82             my $basic_public = $child_key->get_basic_key;
83              
84             =head1 DESCRIPTION
85              
86             This class allows you to create an extended public key instance.
87              
88             You can use an extended public key to:
89              
90             =over 2
91              
92             =item * derive extended keys using a path (only public keys)
93              
94             =item * restore keys from serialized base58 format
95              
96             =back
97              
98             see L<Bitcoin::Crypto::Network> if you want to work with other networks than Bitcoin Mainnet.
99              
100             =head1 METHODS
101              
102             =head2 new
103              
104             Constructor is reserved for internal and advanced use only. Use L</from_serialized> and
105             L</from_serialized_base58> instead.
106              
107             =head2 to_serialized
108              
109             $serialized_key = $object->to_serialized()
110              
111             Returns the key serialized in format specified in BIP32 as byte string.
112              
113             =head2 to_serialized_base58
114              
115             $serialized_key = $object->to_serialized_base58()
116              
117             Behaves the same as to_serialized(), but performs Base58Check encoding on the resulting byte string.
118              
119             =head2 from_serialized
120              
121             $key_object = $class->from_serialized($serialized, $network = undef)
122              
123             Tries to unserialize byte string C<$serialized> with format specified in BIP32.
124              
125             Dies on errors. If multiple networks match serialized data specify C<$network> manually (id of the network) to avoid exception.
126              
127             =head2 from_serialized_base58
128              
129             $key_object = $class->from_serialized_base58($base58, $network = undef)
130              
131             Same as from_serialized, but performs Base58Check decoding on C<$base58> argument.
132              
133             =head2 set_network
134              
135             $key_object = $object->set_network($val)
136              
137             Change key's network state to C<$val>. It can be either network name present in Bitcoin::Crypto::Network package or an instance of this class.
138              
139             Returns current key instance.
140              
141             =head2 get_basic_key
142              
143             $basic_key_object = $object->get_basic_key()
144              
145             Returns the key in basic format: L<Bitcoin::Crypto::Key::Public>
146              
147             =head2 derive_key
148              
149             $derived_key_object = $object->derive_key($path)
150              
151             Performs extended key derivation as specified in BIP32 on the current key with C<$path>. Dies on error.
152              
153             See BIP32 document for details on derivation paths and methods.
154              
155             Note that public keys cannot derive private keys and your derivation path must start with M (capital m).
156              
157             Returns a new extended key instance - result of a derivation.
158              
159             =head2 get_fingerprint
160              
161             $fingerprint = $object->get_fingerprint($len = 4)
162              
163             Returns a fingerprint of the extended key of C<$len> length (byte string)
164              
165             =head1 EXCEPTIONS
166              
167             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:
168              
169             =over 2
170              
171             =item * KeyDerive - key couldn't be derived correctly
172              
173             =item * KeyCreate - key couldn't be created correctly
174              
175             =item * NetworkConfig - incomplete or corrupted network configuration
176              
177             =back
178              
179             =head1 SEE ALSO
180              
181             =over 2
182              
183             =item L<Bitcoin::Crypto::Key::ExtPrivate>
184              
185             =item L<Bitcoin::Crypto::Network>
186              
187             =back
188              
189             =cut
190