File Coverage

blib/lib/Bitcoin/Crypto/Key/ExtPublic.pm
Criterion Covered Total %
statement 45 45 100.0
branch 3 6 50.0
condition n/a
subroutine 12 12 100.0
pod n/a
total 60 63 95.2


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::ExtPublic;
2             $Bitcoin::Crypto::Key::ExtPublic::VERSION = '1.008';
3 8     8   68164 use v5.10;
  8         39  
4 8     8   50 use strict;
  8         23  
  8         199  
5 8     8   43 use warnings;
  8         21  
  8         230  
6 8     8   584 use Moo;
  8         7274  
  8         61  
7 8     8   5859 use Crypt::Mac::HMAC qw(hmac);
  8         4848  
  8         526  
8 8     8   79 use Scalar::Util qw(blessed);
  8         20  
  8         360  
9              
10 8     8   524 use Bitcoin::Crypto::Config;
  8         22  
  8         278  
11 8     8   475 use Bitcoin::Crypto::Helpers qw(new_bigint ensure_length add_ec_points);
  8         31  
  8         475  
12 8     8   58 use Bitcoin::Crypto::Exception;
  8         22  
  8         245  
13              
14 8     8   60 use namespace::clean;
  8         19  
  8         67  
15              
16             with "Bitcoin::Crypto::Role::ExtendedKey";
17              
18 370     370   1272 sub _is_private { 0 }
19              
20             sub _derive_key_partial
21             {
22 15     15   41 my ($self, $child_num, $hardened) = @_;
23              
24 15 50       51 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         48 my $hmac_data = $self->raw_key("public_compressed");
30              
31             # child number - 4 bytes
32 15         97 $hmac_data .= ensure_length pack("N", $child_num), 4;
33              
34 15         214 my $data = hmac("SHA512", $self->chain_code, $hmac_data);
35 15         43 my $chain_code = substr $data, 32, 32;
36              
37 15         67 my $n_order = new_bigint(pack "H*", $self->key_instance->curve2hash->{order});
38 15         3332 my $number = new_bigint(substr $data, 0, 32);
39 15 50       3179 Bitcoin::Crypto::Exception::KeyDerive->raise(
40             "key $child_num in sequence was found invalid"
41             ) if $number->bge($n_order);
42              
43 15         476 my $key = $self->_create_key(substr $data, 0, 32);
44 15         151 my $point = $key->export_key_raw("public");
45 15         54 my $parent_point = $self->raw_key("public");
46 15         61 $point = add_ec_points($point, $parent_point);
47              
48 15 50       51 Bitcoin::Crypto::Exception::KeyDerive->raise(
49             "key $child_num in sequence was found invalid"
50             ) unless defined $point;
51              
52 15         93 return (blessed $self)->new(
53             $point,
54             $chain_code,
55             $child_num,
56             $self->get_fingerprint,
57             $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 to_serialized
103              
104             $serialized_key = $object->to_serialized()
105              
106             Returns the key serialized in format specified in BIP32 as byte string.
107              
108             =head2 to_serialized_base58
109              
110             $serialized_key = $object->to_serialized_base58()
111              
112             Behaves the same as to_serialized(), but performs Base58Check encoding on the resulting byte string.
113              
114             =head2 from_serialized
115              
116             $key_object = $class->from_serialized($serialized, $network = undef)
117              
118             Tries to unserialize byte string C<$serialized> with format specified in BIP32.
119              
120             Dies on errors. If multiple networks match serialized data specify C<$network> manually (id of the network) to avoid exception.
121              
122             =head2 from_serialized_base58
123              
124             $key_object = $class->from_serialized_base58($base58, $network = undef)
125              
126             Same as from_serialized, but performs Base58Check decoding on C<$base58> argument.
127              
128             =head2 set_network
129              
130             $key_object = $object->set_network($val)
131              
132             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.
133              
134             Returns current key instance.
135              
136             =head2 get_basic_key
137              
138             $basic_key_object = $object->get_basic_key()
139              
140             Returns the key in basic format: L<Bitcoin::Crypto::Key::Public>
141              
142             =head2 derive_key
143              
144             $derived_key_object = $object->derive_key($path)
145              
146             Performs extended key derivation as specified in BIP32 on the current key with C<$path>. Dies on error.
147              
148             See BIP32 document for details on derivation paths and methods.
149              
150             Note that public keys cannot derive private keys and your derivation path must start with M (capital m).
151              
152             Returns a new extended key instance - result of a derivation.
153              
154             =head2 get_fingerprint
155              
156             $fingerprint = $object->get_fingerprint($len = 4)
157              
158             Returns a fingerprint of the extended key of C<$len> length (byte string)
159              
160             =head1 EXCEPTIONS
161              
162             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:
163              
164             =over 2
165              
166             =item * KeyDerive - key couldn't be derived correctly
167              
168             =item * KeyCreate - key couldn't be created correctly
169              
170             =item * NetworkConfig - incomplete or corrupted network configuration
171              
172             =back
173              
174             =head1 SEE ALSO
175              
176             =over 2
177              
178             =item L<Bitcoin::Crypto::Key::ExtPrivate>
179              
180             =item L<Bitcoin::Crypto::Network>
181              
182             =back
183              
184             =cut
185