File Coverage

blib/lib/Bitcoin/Crypto/Key/Public.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 10 80.0
condition 9 9 100.0
subroutine 16 16 100.0
pod 3 5 60.0
total 85 89 95.5


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Key::Public;
2             $Bitcoin::Crypto::Key::Public::VERSION = '1.008';
3 10     10   964 use v5.10;
  10         41  
4 10     10   59 use strict;
  10         26  
  10         256  
5 10     10   51 use warnings;
  10         138  
  10         324  
6 10     10   60 use Moo;
  10         27  
  10         91  
7              
8 10     10   9235 use Bitcoin::Crypto::Script;
  10         35  
  10         514  
9 10     10   78 use Bitcoin::Crypto::Base58 qw(encode_base58check);
  10         58  
  10         600  
10 10     10   64 use Bitcoin::Crypto::Bech32 qw(encode_segwit);
  10         32  
  10         408  
11 10     10   66 use Bitcoin::Crypto::Config;
  10         29  
  10         286  
12 10     10   59 use Bitcoin::Crypto::Helpers qw(hash160);
  10         36  
  10         444  
13              
14 10     10   63 use namespace::clean;
  10         26  
  10         99  
15              
16             with "Bitcoin::Crypto::Role::BasicKey";
17              
18 144     144   588 sub _is_private { 0 }
19              
20             sub key_hash
21             {
22 45     45 0 104 my ($self) = @_;
23 45         137 my $pubkey = $self->to_bytes();
24 45         169 return hash160($pubkey);
25             }
26              
27             sub witness_program
28             {
29 11     11 0 27 my ($self) = @_;
30              
31 11         31 return pack("C", Bitcoin::Crypto::Config::witness_version) . $self->key_hash;
32             }
33              
34             sub get_legacy_address
35             {
36 25     25 1 1568 my ($self) = @_;
37              
38 25 100 100     128 Bitcoin::Crypto::Exception::AddressGenerate->raise(
39             'legacy addresses can only be created with BIP44 in legacy (BIP44) mode'
40             ) if $self->has_purpose && $self->purpose != 44;
41              
42 23         107 my $pkh = $self->network->p2pkh_byte . $self->key_hash;
43 23         423 return encode_base58check($pkh);
44             }
45              
46             sub get_compat_address
47             {
48 13     13 1 3738 my ($self) = @_;
49              
50             # network field is not required, lazy check for completeness
51 13 50       71 Bitcoin::Crypto::Exception::NetworkConfig->raise(
52             "this network does not support segregated witness"
53             ) unless $self->network->supports_segwit;
54              
55 13 100 100     86 Bitcoin::Crypto::Exception::AddressGenerate->raise(
56             'compat addresses can only be created with BIP44 in compat (BIP49) mode'
57             ) if $self->has_purpose && $self->purpose != 49;
58              
59 11         191 my $program = Bitcoin::Crypto::Script->new(network => $self->network);
60 11         309 $program->add_operation("OP_" . Bitcoin::Crypto::Config::witness_version)
61             ->push_bytes($self->key_hash);
62 11         52 return $program->get_legacy_address;
63             }
64              
65             sub get_segwit_address
66             {
67 13     13 1 3536 my ($self) = @_;
68              
69             # network field is not required, lazy check for completeness
70 13 50       66 Bitcoin::Crypto::Exception::NetworkConfig->raise(
71             "this network does not support segregated witness"
72             ) unless $self->network->supports_segwit;
73              
74 13 100 100     84 Bitcoin::Crypto::Exception::AddressGenerate->raise(
75             'segwit addresses can only be created with BIP44 in segwit (BIP84) mode'
76             ) if $self->has_purpose && $self->purpose != 84;
77              
78 11         61 return encode_segwit($self->network->segwit_hrp, $self->witness_program);
79             }
80              
81             1;
82              
83             __END__
84             =head1 NAME
85              
86             Bitcoin::Crypto::Key::Public - Bitcoin public keys
87              
88             =head1 SYNOPSIS
89              
90             use Bitcoin::Crypto::Key::Public;
91              
92             $pub = Bitcoin::Crypto::Key::Public->from_hex($asn_hex);
93              
94             # verify signature (it has to be byte string, see perlpacktut)
95              
96             $pub->verify_message(pack("a*", "Hello world"), $sig);
97              
98             # getting address from public key (p2wpkh)
99              
100             my $address = $pub->get_segwit_address();
101              
102             =head1 DESCRIPTION
103              
104             This class allows you to create a public key instance.
105              
106             You can use a public key to:
107              
108             =over 2
109              
110             =item * verify messages
111              
112             =item * create addresses: legacy (p2pkh), compatibility (p2sh(p2wpkh)) and segwit (p2wpkh).
113              
114             =back
115              
116             =head1 METHODS
117              
118             =head2 from_bytes
119              
120             $key_object = $class->from_bytes($data)
121              
122             Use this method to create a PublicKey instance from a byte string.
123             Data C<$data> must represent a public key in ASN X9.62 format.
124              
125             Returns class instance.
126              
127             =head2 new
128              
129             $key_object = $class->new($data)
130              
131             This works exactly the same as from_bytes
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