File Coverage

blib/lib/Bitcoin/Crypto/Key/Public.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 10 80.0
condition n/a
subroutine 16 16 100.0
pod 3 5 60.0
total 76 80 95.0


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::Public;
2             $Bitcoin::Crypto::Key::Public::VERSION = '1.008_01'; # TRIAL
3             $Bitcoin::Crypto::Key::Public::VERSION = '1.00801';
4 10     10   935 use v5.10;
  10         50  
5 10     10   60 use strict;
  10         31  
  10         243  
6 10     10   73 use warnings;
  10         20  
  10         335  
7 10     10   112 use Moo;
  10         41  
  10         71  
8              
9 10     10   9534 use Bitcoin::Crypto::Script;
  10         38  
  10         433  
10 10     10   103 use Bitcoin::Crypto::Base58 qw(encode_base58check);
  10         23  
  10         588  
11 10     10   75 use Bitcoin::Crypto::Bech32 qw(encode_segwit);
  10         34  
  10         517  
12 10     10   79 use Bitcoin::Crypto::Config;
  10         24  
  10         365  
13 10     10   69 use Bitcoin::Crypto::Helpers qw(hash160);
  10         22  
  10         545  
14              
15 10     10   74 use namespace::clean;
  10         23  
  10         149  
16              
17             with qw(Bitcoin::Crypto::Role::BasicKey);
18              
19 144     144   882 sub _is_private { 0 }
20              
21             sub key_hash
22             {
23 45     45 0 99 my ($self) = @_;
24 45         183 my $pubkey = $self->to_bytes();
25 45         201 return hash160($pubkey);
26             }
27              
28             sub witness_program
29             {
30 11     11 0 27 my ($self) = @_;
31              
32 11         31 return pack('C', Bitcoin::Crypto::Config::witness_version) . $self->key_hash;
33             }
34              
35             sub get_legacy_address
36             {
37 25     25 1 1617 my ($self) = @_;
38              
39 25 100       83 Bitcoin::Crypto::Exception::AddressGenerate->raise(
40             'legacy addresses can only be created with BIP44 in legacy (BIP44) mode'
41             ) unless $self->has_purpose(44);
42              
43 23         135 my $pkh = $self->network->p2pkh_byte . $self->key_hash;
44 23         478 return encode_base58check($pkh);
45             }
46              
47             sub get_compat_address
48             {
49 13     13 1 4476 my ($self) = @_;
50              
51             # network field is not required, lazy check for completeness
52 13 50       74 Bitcoin::Crypto::Exception::NetworkConfig->raise(
53             'this network does not support segregated witness'
54             ) unless $self->network->supports_segwit;
55              
56 13 100       50 Bitcoin::Crypto::Exception::AddressGenerate->raise(
57             'compat addresses can only be created with BIP44 in compat (BIP49) mode'
58             ) unless $self->has_purpose(49);
59              
60 11         206 my $program = Bitcoin::Crypto::Script->new(network => $self->network);
61 11         298 $program->add_operation('OP_' . Bitcoin::Crypto::Config::witness_version)
62             ->push_bytes($self->key_hash);
63 11         66 return $program->get_legacy_address;
64             }
65              
66             sub get_segwit_address
67             {
68 13     13 1 3810 my ($self) = @_;
69              
70             # network field is not required, lazy check for completeness
71 13 50       79 Bitcoin::Crypto::Exception::NetworkConfig->raise(
72             'this network does not support segregated witness'
73             ) unless $self->network->supports_segwit;
74              
75 13 100       61 Bitcoin::Crypto::Exception::AddressGenerate->raise(
76             'segwit addresses can only be created with BIP44 in segwit (BIP84) mode'
77             ) unless $self->has_purpose(84);
78              
79 11         71 return encode_segwit($self->network->segwit_hrp, $self->witness_program);
80             }
81              
82             1;
83              
84             __END__
85             =head1 NAME
86              
87             Bitcoin::Crypto::Key::Public - Bitcoin public keys
88              
89             =head1 SYNOPSIS
90              
91             use Bitcoin::Crypto::Key::Public;
92              
93             $pub = Bitcoin::Crypto::Key::Public->from_hex($asn_hex);
94              
95             # verify signature (it has to be byte string, see perlpacktut)
96              
97             $pub->verify_message(pack('a*', 'Hello world'), $sig);
98              
99             # getting address from public key (p2wpkh)
100              
101             my $address = $pub->get_segwit_address();
102              
103             =head1 DESCRIPTION
104              
105             This class allows you to create a public key instance.
106              
107             You can use a public key to:
108              
109             =over 2
110              
111             =item * verify messages
112              
113             =item * create addresses: legacy (p2pkh), compatibility (p2sh(p2wpkh)) and segwit (p2wpkh).
114              
115             =back
116              
117             =head1 METHODS
118              
119             =head2 new
120              
121             Constructor is reserved for internal and advanced use only. Use L</from_bytes> and
122             L</from_hex> instead.
123              
124             =head2 from_bytes
125              
126             $key_object = $class->from_bytes($data)
127              
128             Use this method to create a PublicKey instance from a byte string.
129             Data C<$data> must represent a public key in ASN X9.62 format.
130              
131             Returns class instance.
132              
133             =head2 to_bytes
134              
135             $bytestring = $object->to_bytes()
136              
137             Does the opposite of C<from_bytes> on a target object
138              
139             =head2 from_hex
140              
141             $key_object = $class->from_hex($hex)
142              
143             Use this method to create a public key instance from a hexadecimal number. Packs the number and runs it through C<from_bytes>.
144              
145             Returns class instance.
146              
147             =head2 to_hex
148              
149             $hex_string = $object->to_hex()
150              
151             Does the opposite of from_hex on a target object
152              
153             =head2 set_compressed
154              
155             $key_object = $object->set_compressed($val)
156              
157             Change key's compression state to C<$val> (C<1>/C<0>). This will change the address.
158             If C<$val> is omitted it is set to C<1>.
159              
160             Returns current key instance.
161              
162             =head2 set_network
163              
164             $key_object = $object->set_network($val)
165              
166             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.
167              
168             Returns current key instance.
169              
170             =head2 verify_message
171              
172             $signature_valid = $object->verify_message($message, $signature, $algo = 'sha256')
173              
174             Verifies C<$signature> against digest of C<$message> (with C<$algo> digest algorithm) using public key.
175              
176             C<$algo> must be available in Digest package.
177              
178             Returns boolean.
179              
180             Character encoding note: C<$message> should be encoded in the proper encoding before passing it to this method. Passing Unicode string will cause the function to fail. You can encode like this (for UTF-8):
181              
182             use Encode qw(encode);
183             $message = encode('UTF-8', $message);
184              
185             =head2 get_legacy_address
186              
187             $address_string = $object->get_legacy_address()
188              
189             Returns string containing Base58Check encoded public key hash (p2pkh address).
190              
191             If the public key was obtained through BIP44 derivation scheme, this method will check whether the purpose was C<44> and raise an exception otherwise.
192             If you wish to generate this address anyway, call L</clear_purpose>.
193              
194             =head2 get_compat_address
195              
196             $address_string = $object->get_compat_address()
197              
198             Returns string containing Base58Check encoded script hash containing a witness program for compatibility purposes (p2sh(p2wpkh) address)
199              
200             If the public key was obtained through BIP44 derivation scheme, this method will check whether the purpose was C<49> and raise an exception otherwise.
201             If you wish to generate this address anyway, call L</clear_purpose>.
202              
203             =head2 get_segwit_address
204              
205             $address_string = $object->get_segwit_address()
206              
207             Returns string containing Bech32 encoded witness program (p2wpkh address)
208              
209             If the public key was obtained through BIP44 derivation scheme, this method will check whether the purpose was C<84> and raise an exception otherwise.
210             If you wish to generate this address anyway, call L</clear_purpose>.
211              
212             =head2 clear_purpose
213              
214             $object->clear_purpose;
215              
216             Clears the purpose of this key instance, removing safety checks on address generation.
217              
218             =head1 EXCEPTIONS
219              
220             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:
221              
222             =over 2
223              
224             =item * KeyCreate - key couldn't be created correctly
225              
226             =item * Verify - couldn't verify the message correctly
227              
228             =item * NetworkConfig - incomplete or corrupted network configuration
229              
230             =item * AddressGenerate - address could not be generated (see BIP44 constraint notes)
231              
232             =back
233              
234             =head1 SEE ALSO
235              
236             =over 2
237              
238             =item L<Bitcoin::Crypto::Key::Private>
239              
240             =item L<Bitcoin::Crypto::Network>
241              
242             =item L<Bitcoin::Crypto::Base58>
243              
244             =item L<Bitcoin::Crypto::Bech32>
245              
246             =back
247              
248             =cut
249