File Coverage

blib/lib/Bitcoin/Crypto/Script.pm
Criterion Covered Total %
statement 81 85 95.2
branch 11 22 50.0
condition 5 9 55.5
subroutine 23 23 100.0
pod 8 9 88.8
total 128 148 86.4


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Script;
2             $Bitcoin::Crypto::Script::VERSION = '1.008';
3 11     11   66648 use v5.10;
  11         48  
4 11     11   65 use strict;
  11         25  
  11         237  
5 11     11   57 use warnings;
  11         36  
  11         301  
6 11     11   590 use Moo;
  11         7135  
  11         55  
7 11     11   6272 use Types::Standard qw(ArrayRef Str);
  11         112964  
  11         119  
8 11     11   20497 use Crypt::Digest::SHA256 qw(sha256);
  11         5855  
  11         656  
9              
10 11     11   3492 use Bitcoin::Crypto::Base58 qw(encode_base58check);
  11         32  
  11         650  
11 11     11   4953 use Bitcoin::Crypto::Bech32 qw(encode_segwit);
  11         30  
  11         642  
12 11     11   85 use Bitcoin::Crypto::Config;
  11         46  
  11         266  
13 11     11   63 use Bitcoin::Crypto::Helpers qw(hash160 hash256 verify_bytestring);
  11         25  
  11         557  
14 11     11   68 use Bitcoin::Crypto::Exception;
  11         22  
  11         243  
15              
16 11     11   57 use namespace::clean;
  11         22  
  11         94  
17              
18             with "Bitcoin::Crypto::Role::Network";
19              
20             # list of significant opcodes
21             our %op_codes = (
22             FALSE => {
23             code => "\x00",
24             },
25             PUSHDATA1 => {
26             code => "\x4c",
27             },
28             PUSHDATA2 => {
29             code => "\x4d",
30             },
31             PUSHDATA4 => {
32             code => "\x4e",
33             },
34             "1NEGATE" => {
35             code => "\x4f",
36             },
37             RESERVED => {
38             code => "\x50",
39             },
40             TRUE => {
41             code => "\x51",
42             },
43             NOP => {
44             code => "\x61",
45             },
46             VER => {
47             code => "\x62",
48             },
49             IF => {
50             code => "\x63",
51             },
52             NOTIF => {
53             code => "\x64",
54             },
55             VERIF => {
56             code => "\x65",
57             },
58             VERNOTIF => {
59             code => "\x66",
60             },
61             ELSE => {
62             code => "\x67",
63             },
64             ENDIF => {
65             code => "\x68",
66             },
67             VERIFY => {
68             code => "\x69",
69             },
70             RETURN => {
71             code => "\x6a",
72             },
73             TOALTSTACK => {
74             code => "\x6b",
75             },
76             FROMALTSTACK => {
77             code => "\x6c",
78             },
79             "2DROP" => {
80             code => "\x6d",
81             },
82             "2DUP" => {
83             code => "\x6e",
84             },
85             "3DUP" => {
86             code => "\x6f",
87             },
88             "2OVER" => {
89             code => "\x70",
90             },
91             "2ROT" => {
92             code => "\x71",
93             },
94             "2SWAP" => {
95             code => "\x72",
96             },
97             IFDUP => {
98             code => "\x73",
99             },
100             DEPTH => {
101             code => "\x74",
102             },
103             DROP => {
104             code => "\x75",
105             },
106             DUP => {
107             code => "\x76",
108             },
109             NIP => {
110             code => "\x77",
111             },
112             OVER => {
113             code => "\x78",
114             },
115             PICK => {
116             code => "\x79",
117             },
118             ROLL => {
119             code => "\x7a",
120             },
121             ROT => {
122             code => "\x7b",
123             },
124             SWAP => {
125             code => "\x7c",
126             },
127             TUCK => {
128             code => "\x7d",
129             },
130             SIZE => {
131             code => "\x82",
132             },
133             EQUAL => {
134             code => "\x87",
135             },
136             EQUALVERIFY => {
137             code => "\x88",
138             },
139             RESERVED1 => {
140             code => "\x89",
141             },
142             RESERVED2 => {
143             code => "\x8a",
144             },
145             "1ADD" => {
146             code => "\x8b",
147             },
148             "1SUB" => {
149             code => "\x8c",
150             },
151             NEGATE => {
152             code => "\x8f",
153             },
154             ABS => {
155             code => "\x90",
156             },
157             NOT => {
158             code => "\x91",
159             },
160             ONOTEQUAL => {
161             code => "\x92",
162             },
163             ADD => {
164             code => "\x93",
165             },
166             SUB => {
167             code => "\x94",
168             },
169             BOOLAND => {
170             code => "\x9a",
171             },
172             BOOLOR => {
173             code => "\x9b",
174             },
175             NUMEQUAL => {
176             code => "\x9c",
177             },
178             NUMEQUALVERIFY => {
179             code => "\x9d",
180             },
181             NUMNOTEQUAL => {
182             code => "\x9e",
183             },
184             LESSTHAN => {
185             code => "\x9f",
186             },
187             GREATERTHAN => {
188             code => "\xa0",
189             },
190             LESSTHANOREQUAL => {
191             code => "\xa1",
192             },
193             GREATERTHANOREQUAL => {
194             code => "\xa2",
195             },
196             MIN => {
197             code => "\xa3",
198             },
199             MAX => {
200             code => "\xa4",
201             },
202             WITHIN => {
203             code => "\xa5",
204             },
205             RIPEMD160 => {
206             code => "\xa6",
207             },
208             SHA1 => {
209             code => "\xa7",
210             },
211             SHA256 => {
212             code => "\xa8",
213             },
214             HASH160 => {
215             code => "\xa9",
216             },
217             HASH256 => {
218             code => "\xaa",
219             },
220             CODESEPARATOR => {
221             code => "\xab",
222             },
223             CHECKSIG => {
224             code => "\xac",
225             },
226             CHECKSIGVERIFY => {
227             code => "\xad",
228             },
229             CHECKMULTISIG => {
230             code => "\xae",
231             },
232             CHECKMULTISIGVERIFY => {
233             code => "\xaf",
234             },
235             CHECKLOCKTIMEVERFIY => {
236             code => "\xb1",
237             },
238             CHECKSEQUENCEVERIFY => {
239             code => "\xb2",
240             },
241             );
242              
243             $op_codes{0} = $op_codes{FALSE};
244             $op_codes{1} = $op_codes{TRUE};
245              
246             for (2 .. 16) {
247              
248             # OP_N - starts with 0x52, up to 0x60
249             $op_codes{$_} = {
250             code => pack("C", 0x50 + $_),
251             };
252             }
253              
254             has "operations" => (
255             is => "rw",
256             isa => ArrayRef [Str],
257             default => sub { [] },
258             );
259              
260             sub _get_op_code
261             {
262 42     42   115 my ($context, $op_code) = @_;
263 42 100 33     295 if ($op_code =~ /^OP_(.+)/) {
    50 33        
264 24         62 $op_code = $1;
265 24         140 return $op_codes{$op_code}{code};
266             }
267             elsif ($op_code =~ /^[0-9]+$/ && $op_code >= 1 && $op_code <= 75) {
268              
269             # standard data push - 0x01 up to 0x4b
270 18         90 return pack("C", 0x00 + $op_code);
271             }
272             else {
273 0 0       0 Bitcoin::Crypto::Exception::ScriptOpcode->raise(
274             defined $op_code ? "unknown opcode $op_code" : "undefined opcode variable"
275             );
276             }
277             }
278              
279             sub add_raw
280             {
281 62     62 1 131 my ($self, $bytes) = @_;
282 62         191 verify_bytestring($bytes);
283              
284 62         100 push @{$self->operations}, $bytes;
  62         1209  
285 62         444 return $self;
286             }
287              
288             sub add_operation
289             {
290 42     42 1 157 my ($self, $op_code) = @_;
291 42         102 my $val = $self->_get_op_code($op_code);
292 42         139 $self->add_raw($val);
293 42         121 return $self;
294             }
295              
296             sub push_bytes
297             {
298 20     20 1 305 my ($self, $bytes) = @_;
299 20         65 verify_bytestring($bytes);
300              
301 20         62 my $len = length $bytes;
302 20 50       73 Bitcoin::Crypto::Exception::ScriptPush->raise(
303             "empty data variable"
304             ) unless $len;
305              
306 20 100 100     125 if ($bytes =~ /[\x00-\x10]/ && $len == 1) {
307 1         4 my $num = unpack "C", $bytes;
308 1         5 $self->add_operation("OP_$num");
309             }
310             else {
311 11     11   21963 use bigint;
  11         38276  
  11         59  
312 19 100       204 if ($len <= 75) {
    50          
    0          
    0          
313 18         2058 $self->add_operation($len);
314             }
315             elsif ($len < (2 << 7)) {
316 1         192 $self->add_operation("OP_PUSHDATA1")
317             ->add_raw(pack "C", $len);
318             }
319             elsif ($len < (2 << 15)) {
320 0         0 $self->add_operation("OP_PUSHDATA2")
321             ->add_raw(pack "S", $len);
322             }
323             elsif ($len < (2 << 31)) {
324 0         0 $self->add_operation("OP_PUSHDATA4")
325             ->add_raw(pack "L", $len);
326             }
327             else {
328 0         0 Bitcoin::Crypto::Exception::ScriptPush->raise(
329             "too much data to push onto stack in one operation"
330             );
331             }
332 19         161 $self->add_raw($bytes);
333             }
334 20         55 return $self;
335             }
336              
337             sub get_script
338             {
339 31     31 1 121 my ($self) = @_;
340 31         58 return join "", @{$self->operations};
  31         555  
341             }
342              
343             sub get_script_hash
344             {
345 19     19 1 41 my ($self) = @_;
346 19         70 return hash160($self->get_script);
347             }
348              
349             sub witness_program
350             {
351 4     4 0 9 my ($self) = @_;
352              
353 4         10 return pack("C", Bitcoin::Crypto::Config::witness_version) . sha256($self->get_script);
354             }
355              
356             sub get_legacy_address
357             {
358 19     19 1 2488 my ($self) = @_;
359 19         107 return encode_base58check($self->network->p2sh_byte . $self->get_script_hash);
360             }
361              
362             sub get_compat_address
363             {
364 4     4 1 2553 my ($self) = @_;
365              
366             # network field is not required, lazy check for completeness
367 4 50       20 Bitcoin::Crypto::Exception::NetworkConfig->raise(
368             "this network does not support segregated witness"
369             ) unless $self->network->supports_segwit;
370              
371 4         101 my $program = Bitcoin::Crypto::Script->new(network => $self->network);
372 4         92 $program->add_operation("OP_" . Bitcoin::Crypto::Config::witness_version)
373             ->push_bytes(sha256($self->get_script));
374 4         11 return $program->get_legacy_address;
375             }
376              
377             sub get_segwit_address
378             {
379 4     4 1 2579 my ($self) = @_;
380              
381             # network field is not required, lazy check for completeness
382 4 50       20 Bitcoin::Crypto::Exception::NetworkConfig->raise(
383             "this network does not support segregated witness"
384             ) unless $self->network->supports_segwit;
385              
386 4         16 return encode_segwit($self->network->segwit_hrp, $self->witness_program);
387             }
388              
389             1;
390              
391             __END__
392             =head1 NAME
393              
394             Bitcoin::Crypto::Script - Bitcoin script representations
395              
396             =head1 SYNOPSIS
397              
398             use Bitcoin::Crypto::Script;
399              
400             my $script = Bitcoin::Crypto::Script->new
401             ->add_operation("OP_1")
402             ->add_operation("OP_TRUE")
403             ->add_operation("OP_EQUAL");
404              
405             # getting serialized script
406             my $serialized = $script->get_script();
407              
408             # getting address from script (p2wsh)
409             my $address = $script->get_segwit_adress();
410              
411             =head1 DESCRIPTION
412              
413             This class allows you to create a bitcoin script representations
414              
415             You can use a script object to:
416              
417             =over 2
418              
419             =item * create a script from opcodes
420              
421             =item * serialize script into byte string
422              
423             =item * create legacy (p2sh), compat (p2sh(p2wsh)) and segwit (p2wsh) adresses
424              
425             =back
426              
427             =head1 METHODS
428              
429             =head2 new
430              
431             $script_object = $class->new($data)
432              
433             A constructor. Returns new script instance
434              
435             =head2 add_operation
436              
437             $script_object = $object->add_operation($opcode)
438              
439             Adds a new opcode at the end of a script. Returns the object instance for chaining.
440              
441             Throws an exception for unknown opcodes.
442              
443             =head2 add_raw
444              
445             $script_object = $object->add_raw($bytes)
446              
447             Adds C<$bytes> at the end of a script.
448             Useful when you need a value in a script that shouldn't be pushed to the execution stack, like the first four bytes after C<PUSHDATA4>.
449              
450             Returns the object instance for chaining.
451              
452             =head2 push_bytes
453              
454             $script_object = $object->push_bytes($bytes)
455              
456             Pushes C<$bytes> to the execution stack at the end of a script, using a minimal push opcode.
457              
458             For example, running C<$script->push_bytes("\x03")> will have the same effect as C<$script->add_operation("OP_3")>.
459              
460             Throws an exception for data exceeding a 4 byte number in length.
461              
462             Returns the object instance for chaining.
463              
464             =head2 get_script
465              
466             $bytestring = $object->get_script()
467              
468             Returns a serialized script as byte string.
469              
470             =head2 get_script_hash
471              
472             $bytestring = $object->get_script_hash()
473              
474             Returns a serialized script parsed with C<HASH160> (ripemd160 of sha256).
475              
476             =head2 set_network
477              
478             $script_object = $object->set_network($val)
479              
480             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.
481              
482             Returns current object instance.
483              
484             =head2 get_legacy_address
485              
486             $address = $object->get_legacy_address()
487              
488             Returns string containing Base58Check encoded script hash (p2sh address)
489              
490             =head2 get_compat_address
491              
492             $address = $object->get_compat_address()
493              
494             Returns string containing Base58Check encoded script hash containing a witness program for compatibility purposes (p2sh(p2wsh) address)
495              
496             =head2 get_segwit_address
497              
498             $address = $object->get_segwit_address()
499              
500             Returns string containing Bech32 encoded witness program (p2wsh address)
501              
502             =head1 EXCEPTIONS
503              
504             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:
505              
506             =over 2
507              
508             =item * ScriptOpcode - unknown opcode was specified
509              
510             =item * ScriptPush - data pushed to the execution stack is invalid
511              
512             =item * NetworkConfig - incomplete or corrupted network configuration
513              
514             =back
515              
516             =head1 SEE ALSO
517              
518             =over 2
519              
520             =item L<Bitcoin::Crypto::Key::Private>
521              
522             =item L<Bitcoin::Crypto::Network>
523              
524             =back
525              
526             =cut
527