File Coverage

blib/lib/Bitcoin/Crypto/Key/ExtPublic.pm
Criterion Covered Total %
statement 51 51 100.0
branch 3 6 50.0
condition n/a
subroutine 14 14 100.0
pod n/a
total 68 71 95.7


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::ExtPublic;
2             $Bitcoin::Crypto::Key::ExtPublic::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Key::ExtPublic::VERSION = '2.00001';
4 9     9   138 use v5.10;
  9         37  
5 9     9   73 use strict;
  9         23  
  9         216  
6 9     9   146 use warnings;
  9         68  
  9         251  
7 9     9   655 use Moo;
  9         7772  
  9         75  
8 9     9   5932 use Crypt::Mac::HMAC qw(hmac);
  9         3902  
  9         638  
9 9     9   697 use Type::Params -sigs;
  9         126392  
  9         93  
10              
11 9     9   5708 use Bitcoin::Crypto::Constants;
  9         27  
  9         299  
12 9     9   581 use Bitcoin::Crypto::Helpers qw(ensure_length add_ec_points);
  9         22  
  9         677  
13 9     9   85 use Bitcoin::Crypto::Types qw(Object HashRef);
  9         21  
  9         94  
14 9     9   32767 use Bitcoin::Crypto::Exception;
  9         34  
  9         221  
15 9     9   631 use Bitcoin::Crypto::BIP44;
  9         22  
  9         195  
16              
17 9     9   53 use namespace::clean;
  9         27  
  9         58  
18              
19             with qw(Bitcoin::Crypto::Role::ExtendedKey);
20              
21 304     304   1535 sub _is_private { 0 }
22              
23             signature_for derive_key_bip44 => (
24             method => Object,
25             positional => [HashRef, {slurpy => 1}],
26             );
27              
28             sub derive_key_bip44
29             {
30             my ($self, $data) = @_;
31             my $path = Bitcoin::Crypto::BIP44->new(
32             %{$data},
33             coin_type => $self,
34             public => 1,
35             );
36              
37             return $self->derive_key($path);
38             }
39              
40             sub _derive_key_partial
41             {
42 17     17   54 my ($self, $child_num, $hardened) = @_;
43              
44 17 50       57 Bitcoin::Crypto::Exception::KeyDerive->raise(
45             'cannot derive hardened key from public key'
46             ) if $hardened;
47              
48             # public key data - SEC compressed form
49 17         64 my $hmac_data = $self->raw_key('public_compressed');
50              
51             # child number - 4 bytes
52 17         134 $hmac_data .= ensure_length pack('N', $child_num), 4;
53              
54 17         242 my $data = hmac('SHA512', $self->chain_code, $hmac_data);
55 17         58 my $chain_code = substr $data, 32, 32;
56              
57 17         73 my $n_order = Math::BigInt->from_hex($self->key_instance->curve2hash->{order});
58 17         4992 my $number = Math::BigInt->from_bytes(substr $data, 0, 32);
59 17 50       1740 Bitcoin::Crypto::Exception::KeyDerive->raise(
60             "key $child_num in sequence was found invalid"
61             ) if $number->bge($n_order);
62              
63 17         621 my $key = $self->_create_key(substr $data, 0, 32);
64 17         184 my $point = $key->export_key_raw('public');
65 17         87 my $parent_point = $self->raw_key('public');
66 17         108 $point = add_ec_points($point, $parent_point);
67              
68 17 50       63 Bitcoin::Crypto::Exception::KeyDerive->raise(
69             "key $child_num in sequence was found invalid"
70             ) unless defined $point;
71              
72 17         78 return $self->new(
73             key_instance => $point,
74             chain_code => $chain_code,
75             child_number => $child_num,
76             parent_fingerprint => $self->get_fingerprint,
77             depth => $self->depth + 1,
78             );
79             }
80              
81             1;
82              
83             __END__
84             =head1 NAME
85              
86             Bitcoin::Crypto::Key::ExtPublic - Bitcoin extended public keys
87              
88             =head1 SYNOPSIS
89              
90             use Bitcoin::Crypto qw(btc_extprv);
91             use Bitcoin::Crypto::Util qw(generate_mnemonic to_format)
92              
93             my $mnemonic = generate_mnemonic;
94             my $key = btc_extprv->from_mnemonic($mnemonic);
95              
96             # derive child public key
97             my $path = "M/0";
98             my $child_key = $key->derive_key($path);
99             my $ser_child_key = to_format [base58 => $child_key->to_serialized];
100             print "Your exported $path child key is: $ser_child_key";
101              
102             # create basic public key
103             my $basic_public = $child_key->get_basic_key;
104              
105             =head1 DESCRIPTION
106              
107             This class allows you to create an extended public key instance.
108              
109             You can use an extended public key to:
110              
111             =over 2
112              
113             =item * derive extended keys using a path (only public keys)
114              
115             =item * restore keys from serialized base58 format
116              
117             =back
118              
119             see L<Bitcoin::Crypto::Network> if you want to work with other networks than Bitcoin Mainnet.
120              
121             =head1 METHODS
122              
123             =head2 new
124              
125             Constructor is reserved for internal and advanced use only. Use L</from_serialized> instead.
126              
127             =head2 to_serialized
128              
129             $serialized_key = $object->to_serialized()
130              
131             Returns the key serialized in format specified in BIP32 as byte string.
132              
133             =head2 to_serialized_base58
134              
135             Deprecated. Use C<< to_format [base58 => $key->to_serialized] >> instead.
136              
137             =head2 from_serialized
138              
139             $key_object = $class->from_serialized($serialized, $network = undef)
140              
141             Tries to unserialize byte string C<$serialized> with format specified in BIP32.
142              
143             Dies on errors. If multiple networks match serialized data specify C<$network>
144             manually (id of the network) to avoid exception.
145              
146             =head2 from_serialized_base58
147              
148             Deprecated. Use C<< $class->from_serialized([base58 => $base58]) >> instead.
149              
150             =head2 set_network
151              
152             $key_object = $object->set_network($val)
153              
154             Change key's network state to C<$val>. It can be either network name present in
155             Bitcoin::Crypto::Network package or an instance of this class.
156              
157             Returns current key instance.
158              
159             =head2 get_basic_key
160              
161             $basic_key_object = $object->get_basic_key()
162              
163             Returns the key in basic format: L<Bitcoin::Crypto::Key::Public>
164              
165             =head2 derive_key
166              
167             $derived_key_object = $object->derive_key($path)
168              
169             Performs extended key derivation as specified in BIP32 on the current key with
170             C<$path>. Dies on error.
171              
172             See BIP32 document for details on derivation paths and methods.
173              
174             Note that public keys cannot derive private keys and your derivation path must
175             start with M (capital m).
176              
177             Returns a new extended key instance - result of a derivation.
178              
179             =head2 derive_key_bip44
180              
181             $derived_key_object = $object->derive_key_bip44(%data)
182              
183             A helper that constructs a L<Bitcoin::Crypto::BIP44> path from C<%data> and
184             calls L</derive_key> with it. In extended public keys, bip44 is always
185             constructed with C<public> setting - it will always derive starting from
186             account, effectively only using C<change> and C<index> attributes.
187              
188             =head2 get_fingerprint
189              
190             $fingerprint = $object->get_fingerprint($len = 4)
191              
192             Returns a fingerprint of the extended key of C<$len> length (byte string)
193              
194             =head1 EXCEPTIONS
195              
196             This module throws an instance of L<Bitcoin::Crypto::Exception> if it
197             encounters an error. It can produce the following error types from the
198             L<Bitcoin::Crypto::Exception> namespace:
199              
200             =over 2
201              
202             =item * KeyDerive - key couldn't be derived correctly
203              
204             =item * KeyCreate - key couldn't be created correctly
205              
206             =item * NetworkConfig - incomplete or corrupted network configuration
207              
208             =back
209              
210             =head1 SEE ALSO
211              
212             =over 2
213              
214             =item L<Bitcoin::Crypto::Key::ExtPrivate>
215              
216             =item L<Bitcoin::Crypto::Network>
217              
218             =back
219              
220             =cut
221