File Coverage

blib/lib/Bitcoin/Crypto/Bech32.pm
Criterion Covered Total %
statement 98 98 100.0
branch 11 12 91.6
condition 13 15 86.6
subroutine 22 22 100.0
pod 2 12 16.6
total 146 159 91.8


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Bech32;
2             $Bitcoin::Crypto::Bech32::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Bech32::VERSION = '2.00001';
4 30     30   73881 use v5.10;
  30         133  
5 30     30   193 use strict;
  30         97  
  30         684  
6 30     30   170 use warnings;
  30         64  
  30         956  
7 30     30   180 use Exporter qw(import);
  30         107  
  30         995  
8 30     30   758 use Type::Params -sigs;
  30         128494  
  30         258  
9              
10 30     30   14385 use Bitcoin::Crypto::Exception;
  30         99  
  30         750  
11 30     30   719 use Bitcoin::Crypto::Util qw(validate_segwit);
  30         73  
  30         1437  
12 30     30   219 use Bitcoin::Crypto::Types qw(ByteStr Str Enum ArrayRef Int);
  30         70  
  30         206  
13              
14             our @EXPORT_OK = qw(
15             translate_5to8
16             translate_8to5
17             encode_bech32
18             decode_bech32
19             encode_segwit
20             decode_segwit
21             get_hrp
22             );
23              
24 30     30   116056 use constant BECH32 => 'bech32';
  30         89  
  30         2237  
25 30     30   210 use constant BECH32M => 'bech32m';
  30         95  
  30         47469  
26              
27             our %EXPORT_TAGS = (all => [@EXPORT_OK]);
28              
29             my $CHECKSUM_SIZE = 6;
30             my $BECH32M_CONSTANT = 0x2bc830a3;
31              
32             my @alphabet = qw(
33             q p z r y 9 x 8
34             g f 2 t v d w 0
35             s 3 j n 5 4 k h
36             c e 6 m u a 7 l
37             );
38              
39             my %alphabet_mapped = map { $alphabet[$_] => $_ } 0 .. $#alphabet;
40              
41             sub polymod
42             {
43 154     154 0 608 my ($values) = @_;
44 154         338 my @consts = (0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3);
45 154         441 my $chk = 1;
46 154         292 for my $val (@$values) {
47 7851         9874 my $b = ($chk >> 25);
48 7851         10114 $chk = ($chk & 0x1ffffff) << 5 ^ $val;
49 7851         10576 for (0 .. 4) {
50 39255 100       62267 $chk ^= ((($b >> $_) & 1) ? $consts[$_] : 0);
51             }
52             }
53 154         727 return $chk;
54             }
55              
56             sub hrp_expand
57             {
58 154     154 0 464 my @hrp = split //, shift;
59 154         253 my (@part1, @part2);
60 154         312 for (@hrp) {
61 738         966 my $val = ord;
62 738         1049 push @part1, $val >> 5;
63 738         1261 push @part2, $val & 31;
64             }
65 154         559 return [@part1, 0, @part2];
66             }
67              
68             sub to_numarr
69             {
70 154     154 0 304 my ($string) = @_;
71              
72 154         1030 return [map { $alphabet_mapped{$_} } split //, $string];
  5867         9594  
73             }
74              
75             sub create_checksum
76             {
77 47     47 0 115 my ($hrp, $data) = @_;
78 47         78 my $polymod = polymod([@{hrp_expand $hrp}, @{to_numarr $data}, (0) x $CHECKSUM_SIZE]) ^ 1;
  47         131  
  47         105  
79 47         181 my $checksum;
80 47         136 for (0 .. $CHECKSUM_SIZE - 1) {
81 282         530 $checksum .= $alphabet[($polymod >> 5 * (5 - $_)) & 31];
82             }
83 47         146 return $checksum;
84             }
85              
86             sub create_checksum_bech32m
87             {
88 12     12 0 27 my ($hrp, $data) = @_;
89 12         17 my $polymod = polymod([@{hrp_expand $hrp}, @{to_numarr $data}, (0) x $CHECKSUM_SIZE]) ^ $BECH32M_CONSTANT;
  12         27  
  12         24  
90 12         43 my $checksum;
91 12         31 for (0 .. $CHECKSUM_SIZE - 1) {
92 72         123 $checksum .= $alphabet[($polymod >> 5 * (5 - $_)) & 31];
93             }
94 12         31 return $checksum;
95             }
96              
97             sub verify_checksum
98             {
99 65     65 0 135 my ($hrp, $data) = @_;
100 65         103 return polymod([@{hrp_expand $hrp}, @{to_numarr $data}]) == 1;
  65         143  
  65         150  
101             }
102              
103             sub verify_checksum_bech32m
104             {
105 30     30 0 64 my ($hrp, $data) = @_;
106 30         41 return polymod([@{hrp_expand $hrp}, @{to_numarr $data}]) == $BECH32M_CONSTANT;
  30         54  
  30         67  
107             }
108              
109             signature_for split_bech32 => (
110             positional => [Str],
111             );
112              
113             sub split_bech32
114             {
115             my ($bech32enc) = @_;
116              
117             $bech32enc = lc $bech32enc
118             if uc $bech32enc eq $bech32enc;
119              
120             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
121             'bech32 string too long'
122             ) if length $bech32enc > 90;
123              
124             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
125             'bech32 string contains mixed case'
126             ) if lc $bech32enc ne $bech32enc;
127              
128             my @parts = split /1/, $bech32enc;
129              
130             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
131             'bech32 separator character missing'
132             ) if @parts < 2;
133              
134             my $data = pop @parts;
135              
136             @parts = (join('1', @parts), $data);
137              
138             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
139             'incorrect length of bech32 human readable part'
140             ) if length $parts[0] < 1 || length $parts[0] > 83;
141              
142             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
143             'illegal characters in bech32 human readable part'
144             ) if $parts[0] !~ /\A[\x21-\x7e]+\z/;
145              
146             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
147             'incorrect length of bech32 data part'
148             ) if length $parts[1] < 6;
149              
150             my $chars = join '', @alphabet;
151             Bitcoin::Crypto::Exception::Bech32InputFormat->raise(
152             'illegal characters in bech32 data part'
153             ) if $parts[1] !~ /\A[$chars]+\z/;
154              
155             return @parts;
156             }
157              
158             signature_for translate_5to8 => (
159             positional => [ArrayRef [Int]],
160             );
161              
162             # used during segwit address decoding
163             sub translate_5to8
164             {
165             my ($values_ref) = @_;
166             my @enc_values = @{$values_ref};
167              
168             my $bits = unpack 'B*', pack 'C*', @enc_values;
169             $bits = join '', map { substr $_, 3 } unpack '(a8)*', $bits;
170              
171             my $length_padded = length $bits;
172             my $padding = $length_padded % 8;
173             $bits =~ s/0{$padding}$//;
174              
175             Bitcoin::Crypto::Exception::Bech32InputData->raise(
176             'incorrect padding encoded in bech32'
177             ) if length($bits) % 8 != 0 || length($bits) < $length_padded - 4;
178              
179             my @data = unpack '(a8)*', $bits;
180             my $result = '';
181             for my $bitstr (@data) {
182             $result .= pack 'B8', $bitstr;
183             }
184             return $result;
185             }
186              
187             signature_for translate_8to5 => (
188             positional => [ByteStr],
189             );
190              
191             # used during segwit address encoding
192             sub translate_8to5
193             {
194             my ($bytes) = @_;
195              
196             my @data = unpack '(a5)*', unpack 'B*', $bytes;
197             my @result;
198             for my $bitstr (@data) {
199             my $pad = 5 - length $bitstr;
200             my $num = unpack 'C', pack 'B*', "000$bitstr" . 0 x $pad;
201             push @result, $num;
202             }
203              
204             return \@result;
205             }
206              
207             sub encode_base32
208             {
209 59     59 0 105 my ($array) = @_;
210              
211 59         105 my $result = '';
212 59         85 for my $num (@{$array}) {
  59         130  
213 2068 50 33     4777 Bitcoin::Crypto::Exception::Bech32InputData->raise(
214             'incorrect number to be encoded in bech32: must be between 0 and 31'
215             ) if $num < 0 || $num > 31;
216 2068         3025 $result .= $alphabet[$num];
217             }
218              
219 59         166 return $result;
220             }
221              
222             sub decode_base32
223             {
224 60     60 0 205 my ($encoded) = @_;
225              
226 60         403 my @enc_values = map { $alphabet_mapped{$_} } split //, $encoded;
  2207         3098  
227              
228 60         379 return \@enc_values;
229             }
230              
231             signature_for encode_bech32 => (
232             positional => [Str, ArrayRef [Int], Enum [BECH32M, BECH32], {default => BECH32M}],
233             );
234              
235             sub encode_bech32
236             {
237             my ($hrp, $data, $type) = @_;
238              
239             my $result = encode_base32($data);
240             my $checksum;
241              
242             if ($type eq BECH32) {
243             $checksum = create_checksum($hrp, $result);
244             }
245             elsif ($type eq BECH32M) {
246             $checksum = create_checksum_bech32m($hrp, $result);
247             }
248              
249             return $hrp . 1 . $result . $checksum;
250             }
251              
252             signature_for encode_segwit => (
253             positional => [Str, ByteStr],
254             );
255              
256             sub encode_segwit
257             {
258             my ($hrp, $bytes) = @_;
259              
260             my $version = validate_segwit($bytes);
261             return encode_bech32($hrp, [$version, @{translate_8to5(substr $bytes, 1)}], $version == 0 ? BECH32 : BECH32M);
262             }
263              
264             sub decode_bech32
265             {
266 81     81 1 78222 my ($hrp, $data) = split_bech32 @_;
267              
268 65         115 my $type;
269 65 100       174 $type = BECH32
270             if verify_checksum($hrp, $data);
271 65 100 100     333 $type = BECH32M
272             if !$type && verify_checksum_bech32m($hrp, $data);
273              
274 65 100       240 Bitcoin::Crypto::Exception::Bech32InputChecksum->raise(
275             'incorrect bech32 checksum'
276             ) unless $type;
277              
278 60         287 return ($hrp, decode_base32(substr $data, 0, -$CHECKSUM_SIZE), $type);
279             }
280              
281             sub decode_segwit
282             {
283 39     39 1 74146 my ($hrp, $data, $type) = decode_bech32 @_;
284 34         84 my $ver = shift @{$data};
  34         72  
285              
286 34 100 100     293 Bitcoin::Crypto::Exception::Bech32InputChecksum->raise(
      100        
      100        
287             'wrong bech32 checksum calculated for given segwit program'
288             ) if ($ver == 0 && $type ne BECH32)
289             || ($ver > 0 && $type ne BECH32M);
290              
291 28         165 my $bytes = pack('C', $ver) . translate_5to8 $data;
292 25         144 validate_segwit($bytes);
293              
294 19         88 return $bytes;
295             }
296              
297             sub get_hrp
298             {
299 9     9 0 44 my ($hrp, $data) = split_bech32 @_;
300              
301 9         231 return $hrp;
302             }
303              
304             1;
305              
306             __END__
307              
308             =head1 NAME
309              
310             Bitcoin::Crypto::Bech32 - Bitcoin Bech32 implementation
311              
312             =head1 SYNOPSIS
313              
314             # none exported by default
315             use Bitcoin::Crypto::Bech32 qw(
316             translate_5to8
317             translate_8to5
318             encode_bech32
319             decode_bech32
320             encode_segwit
321             decode_segwit
322             );
323              
324             # witness version - a number from 0 to 16, packed into a byte
325             my $version = pack 'C', 0;
326              
327             # human readable part of the address - a string
328             my $network_hrp = Bitcoin::Crypto::Network->get->segwit_hrp;
329              
330             # handles Bitcoin SegWit adresses
331             my $segwit_address = encode_segwit($network_hrp, $version . $pubkeyhash);
332             my $data_with_version = decode_segwit($segwit_address);
333              
334             # handles custom Bech32 encoding
335             # should start with hello1
336             my $bech32str = encode_bech32('hello', [28, 25, 31, 0, 5], 'bech32');
337             my ($hrp, $data_aref, $type) = decode_bech32($bech32str);
338              
339             =head1 DESCRIPTION
340              
341             Implementation of Bech32 algorithm (BIP-173 and BIP-350 compatible)
342              
343             The module has a couple of layers of encoding, namely:
344              
345             =over
346              
347             =item * 5-to-8 and 8-to-5 bits transformation
348              
349             =item * bech32, which handles checksums and human-readable (HRP) parts
350              
351             =item * segwit, which handles segwit program numbering and validation
352              
353             =back
354              
355             For Bech32-encoded SegWit addresses, use L</encode_segwit> and L</decode_segwit>.
356             For custom uses of Bech32 (not in context of Bitcoin SegWit addresses), use
357             L</encode_bech32> and L</decode_bech32>.
358              
359             B<If in doubt, use segwit functions, not bech32 functions!>
360              
361             =head1 FUNCTIONS
362              
363             This module is based on Exporter. None of the functions are exported by
364             default. Use C<:all> tag to import all the functions at once.
365              
366             =head2 encode_segwit
367              
368             =head2 decode_segwit
369              
370             my $encoded_address = encode_segwit($hrp, $segwit_program);
371              
372             my $segwit_program = decode_segwit($encoded_address);
373              
374             Bech32 encoding / decoding valid for SegWit addresses. Human readable part
375             validation is not included.
376              
377             These functions also perform segwit program validation, see
378             L<Bitcoin::Crypto::Segwit>.
379              
380             Encoding takes two arguments which are a human readable part and a bytestring
381             (segwit program).
382              
383             Decoding takes bech32-encoded string. Returns the entire encoded data
384             (bytestring) along with the segwit program version byte.
385              
386             Encoding scheme (C<bech32> or C<bech32m>) is chosen based on version included
387             in the segwit program.
388              
389             =head2 encode_bech32
390              
391             =head2 decode_bech32
392              
393             my $encoded_bech32 = encode_bech32($hrp, \@data, $type = 'bech32m');
394              
395             my ($hrp, $data_aref, $type) = decode_bech32($encoded_bech32);
396              
397             Basic bech32 encoding / decoding.
398              
399             Encoding takes up to three arguments which are:
400              
401             =over
402              
403             =item * a human readable part
404              
405             =item * an array reference of integer values to be encoded in bech32 (each must
406             be between 0 and 31)
407              
408             =item * optional type, which may be C<'bech32'> or C<'bech32m'> (also available
409             in constant values Bitcoin::Crypto::Bech32::BECH32 and
410             Bitcoin::Crypto::Bech32::BECH32M)
411              
412             =back
413              
414             If omitted, the type will be equal to C<'bech32m'>, which has more robust checksum.
415              
416             Decoding takes a single parameter: a bech32-encoded string and returns a list
417             which has the same values as arguments to C<encode_bech32> function, including
418             C<$type>. This means you can feed both bech32 and bech32m encodings to
419             C<decode_bech32> and the function will identify and return the type for you.
420              
421             B<< These methods are not meant to work with Bitcoin SegWit addresses, use
422             C<encode_segwit> and C<decode_segwit> for that instead. >>
423              
424             =head2 translate_5to8
425              
426             =head2 translate_8to5
427              
428             my $bytestr = translate_5to8(\@int_array);
429              
430             my $int_aref = translate_8to5($bytestr);
431              
432             These are helper functions that implement 5-bit to 8-bit encoding used in
433             bech32 segwit addresses. C<translate_8to5> is used during encoding, and
434             C<translate_5to8> during decoding. They are used as means to store full byte
435             data in bech32 strings, like so:
436              
437             my $data = encode_bech32('hrp', translate_8to5($bytes));
438             my $decoded = translate_5to8(decode_bech32($data));
439              
440             =head1 EXCEPTIONS
441              
442             This module throws an instance of L<Bitcoin::Crypto::Exception> if it
443             encounters an error. It can produce the following error types from the
444             L<Bitcoin::Crypto::Exception> namespace:
445              
446             =over
447              
448             =item * Bech32InputFormat - input was not suitable for bech32 operations due to invalid format
449              
450             =item * Bech32InputData - input was parsed with bech32 operations but contained invalid data
451              
452             =item * Bech32InputChecksum - checksum validation has failed
453              
454             =back
455              
456             =head1 SEE ALSO
457              
458             L<Bitcoin::Crypto::Base58>
459              
460             L<Bitcoin::Crypto::Segwit>
461