1
+ <?php declare (strict_types=1 );
2
+
3
+ namespace BitWasp \Bitcoin \Tests \Script ;
4
+
5
+ use BitWasp \Bitcoin \Crypto \EcAdapter \Adapter \EcAdapterInterface ;
6
+ use BitWasp \Bitcoin \Script \Consensus \NativeConsensus ;
7
+ use BitWasp \Bitcoin \Script \Opcodes ;
8
+ use BitWasp \Bitcoin \Script \Script ;
9
+ use BitWasp \Bitcoin \Script \Interpreter \Interpreter as I ;
10
+ use BitWasp \Bitcoin \Script \ScriptFactory ;
11
+ use BitWasp \Bitcoin \Script \ScriptWitness ;
12
+ use BitWasp \Bitcoin \Transaction \TransactionOutput ;
13
+ use BitWasp \Buffertools \Buffer ;
14
+ use const BitWasp \Bitcoin \Script \Interpreter \TAPROOT_LEAF_TAPSCRIPT ;
15
+
16
+ class TaprootTest extends ConsensusTest
17
+ {
18
+ public function prepareTestData (): array
19
+ {
20
+ $ opcodes = new Opcodes ();
21
+ $ mapOpNames = $ this ->calcMapOpNames ($ opcodes );
22
+ return [
23
+ //[$flags, $returns, $scriptWitness, $scriptSig, $scriptPubKey, $amount, $strTest],
24
+ [0 , true , new ScriptWitness (), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'should return true when segwit & taproot not active ' ],
25
+ [I::VERIFY_WITNESS , true , new ScriptWitness (), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'should return true when taproot not active ' ],
26
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'should return false if scriptWitness empty ' ],
27
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT |I::VERIFY_DISCOURAGE_UPGRADABLE_ANNEX , false , new ScriptWitness (new Buffer (), new Buffer (), new Buffer ("\x50" )), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'VERIFY_DISCOURAGE_UPGRADABLE_ANNEX rejects annex if present ' ],
28
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (new Buffer (), new Buffer (), new Buffer (str_repeat ("A " , 32 ))), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'control size wrong: (under minimum) ' ],
29
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (new Buffer (), new Buffer (), new Buffer (str_repeat ("A " , 33 +32 *128 +1 ))), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'control size wrong: (over maximum) ' ],
30
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (new Buffer (), new Buffer (), new Buffer (str_repeat ("A " , 33 +16 ))), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xabcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234 ' ), 0 , 'control size wrong: ((len-33)%32!=0) ' ],
31
+
32
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , true , new ScriptWitness (Buffer::hex ('b2ecb4b1957d495d55c72e3deabb3d76ed8d33c2496ffdbdc8577b9605ceec84732f6eb3d90c89931f42d0a76499aa2b493f44e53c2c9d74a3565fd8fecc4bbd ' )), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x1dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a ' ), 1 , 'keypath signature ok ' , [new TransactionOutput (1 , new Script (Buffer::hex ("51201dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a " )))]],
33
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('11ecb4b1957d495d55c72e3deabb3d76ed8d33c2496ffdbdc8577b9605ceec84732f6eb3d90c89931f42d0a76499aa2b493f44e53c2c9d74a3565fd8fecc4bbd ' )), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x1dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a ' ), 1 , 'keypath signature r first byte wrong ' , [new TransactionOutput (1 , new Script (Buffer::hex ("51201dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a " )))]],
34
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('b2ecb4b1957d495d55c72e3deabb3d76ed8d33c2496ffdbdc8577b9605ceec84112f6eb3d90c89931f42d0a76499aa2b493f44e53c2c9d74a3565fd8fecc4bbd ' )), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x1dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a ' ), 1 , 'keypath signature s first byte wrong ' , [new TransactionOutput (1 , new Script (Buffer::hex ("51201dcf456c1195e3bd19fe33e52309859253ddc9b95996b0896e36fd3df34eb66a " )))]],
35
+
36
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , true , new ScriptWitness (Buffer::hex ('613f2d05989a9b82d407663c96d9f599428f5e4a3cb450d49c8292ebc2a44fc877b90d2273cc54911b5ae466b1ac10b6e7c8c972f31253eba12c14073ef957e901 ' ),
37
+ Buffer::hex ('0020b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99ba519c ' ),
38
+ Buffer::hex ('c0b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 ' )
39
+ ), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 ' ), 1 , 'tapscript 1of1 checksigadd ' , [new TransactionOutput (1 , new Script (Buffer::hex ("5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " )))]],
40
+
41
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('613f2d05989a9b82d407663c96d9f599428f5e4a3cb450d49c8292ebc2a44fc877b90d2273cc54911b5ae466b1ac10b6e7c8c972f31253eba12c14073ef957e901 ' ),
42
+ Buffer::hex ('0020b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99ba519c ' ),
43
+ Buffer::hex ('c0b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 ' )
44
+ ), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0xfffff82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 ' ), 1 , 'first 2 bytes spk wrong ' , [new TransactionOutput (1 , new Script (Buffer::hex ("5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " )))]],
45
+
46
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('613f2d05989a9b82d407663c96d9f599428f5e4a3cb450d49c8292ebc2a44fc877b90d2273cc54911b5ae466b1ac10b6e7c8c972f31253eba12c14073ef957e901 ' ),
47
+ Buffer::hex ('ff20b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99ba519c ' ),
48
+ Buffer::hex ('c0b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 ' )
49
+ ), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 ' ), 1 , '1st byte script element incorrect ' , [new TransactionOutput (1 , new Script (Buffer::hex ("5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " )))]],
50
+
51
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('613f2d05989a9b82d407663c96d9f599428f5e4a3cb450d49c8292ebc2a44fc877b90d2273cc54911b5ae466b1ac10b6e7c8c972f31253eba12c14073ef957e901 ' ),
52
+ Buffer::hex ('0020b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99ba519c ' ),
53
+ Buffer::hex ('c1b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 ' )
54
+ ), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 ' ), 1 , 'is_square_y bit incorrect ' , [new TransactionOutput (1 , new Script (Buffer::hex ("5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " )))]],
55
+
56
+ [I::VERIFY_WITNESS |I::VERIFY_TAPROOT , false , new ScriptWitness (Buffer::hex ('613f2d05989a9b82d407663c96d9f599428f5e4a3cb450d49c8292ebc2a44fc877b90d2273cc54911b5ae466b1ac10b6e7c8c972f31253eba12c14073ef957e901 ' ),
57
+ Buffer::hex ('0020b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99ba519c ' ),
58
+ Buffer::hex ('c0ffffbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 ' )
59
+ ), new Script (), $ this ->calcScriptFromString ($ mapOpNames , '0x51 0x20 0x070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 ' ), 1 , '1st 2 bytes control hash incorrect ' , [new TransactionOutput (1 , new Script (Buffer::hex ("5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " )))]],
60
+ ];
61
+ }
62
+
63
+ /**
64
+ * @dataProvider getEcAdapters
65
+ * @throws \Exception
66
+ */
67
+ public function testTweakTestCase (EcAdapterInterface $ ec )
68
+ {
69
+ $ privFactory = new \BitWasp \Bitcoin \Key \Factory \PrivateKeyFactory ($ ec );
70
+
71
+ $ privHex = "f698076154c545857fe7072ecb8df962c965b798b1d2b7640da20db3a6fcdb7d " ;
72
+ $ privKey = $ privFactory ->fromHexUncompressed ($ privHex );
73
+ $ pub = $ privKey ->getPublicKey ();
74
+ $ xonly = $ pub ->asXOnlyPublicKey ();
75
+ $ multisig1of1 = ScriptFactory::create ()
76
+ ->opcode (Opcodes::OP_0 )
77
+ ->data ($ xonly ->getBuffer ())
78
+ ->opcode (Opcodes::OP_CHECKSIGADD , Opcodes::OP_1 , Opcodes::OP_NUMEQUAL )
79
+ ->getScript ();
80
+
81
+ $ tree = [
82
+ [TAPROOT_LEAF_TAPSCRIPT , $ multisig1of1 ]
83
+ ];
84
+ $ ret = \BitWasp \Bitcoin \Script \Taproot \taprootConstruct ($ xonly , $ tree );
85
+ list ($ scriptPubKey , $ tweak , $ scripts , $ control ) = $ ret ;
86
+
87
+ $ this ->assertEquals (
88
+ "5120070af82161cbd04c96cd86e7f8c600a9370092b02c3cef2fbd9dcb639b1b84b7 " ,
89
+ $ scriptPubKey ->getHex ()
90
+ );
91
+ $ this ->assertEquals (
92
+ "85a4787be0566335143ad2d60f72b4db97044236515db7ffd733b8f6e10efe64 " ,
93
+ $ tweak ->getHex ()
94
+ );
95
+ $ this ->assertEquals (
96
+ $ multisig1of1 ->getHex (),
97
+ $ scripts [0 ]->getHex ()
98
+ );
99
+ $ this ->assertEquals (
100
+ $ multisig1of1 ->getHex (),
101
+ $ scripts [0 ]->getHex ()
102
+ );
103
+ $ this ->assertEquals (
104
+ "c0b24dbf3e21d269c0da6e5c1da77c8b4041b9ae85aa1747d2db7f9653aa93ed99 " ,
105
+ bin2hex ($ control [0 ])
106
+ );
107
+ }
108
+
109
+ /**
110
+ * @param array $ecAdapterFixtures - array<array<EcAdapterInterface>>
111
+ * @return array - array<array<ConsensusInterface,EcAdapterInterface>>
112
+ */
113
+ public function getConsensusAdapters (array $ ecAdapterFixtures ): array
114
+ {
115
+ $ adapters = [];
116
+ foreach ($ ecAdapterFixtures as $ ecAdapterFixture ) {
117
+ list ($ ecAdapter ) = $ ecAdapterFixture ;
118
+ $ adapters [] = [new NativeConsensus ($ ecAdapter )];
119
+ }
120
+
121
+ return $ adapters ;
122
+ }
123
+ }
0 commit comments