-
Notifications
You must be signed in to change notification settings - Fork 0
/
taproot_test_script_path2.py
195 lines (154 loc) · 7.67 KB
/
taproot_test_script_path2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import BIP350
import Schnorr
import ToolsUnit
'''
Esattamente uguale a taproot_test_script_path2 ma
usando locking script in perfetto stile taproot
ESITO: NON FUNZIONA IN QUESTO MODO! LO STACK NON è VALIDO!
'''
LEAF_VER = b'\xc0'
# internal private and public key
d = 18968816317819169306095104891728354025797295648084455976845396390496379316945
P_point = Schnorr.multiply(d)
if P_point[1] % 2 != 0:
d = Schnorr.n - d
P_point = Schnorr.multiply(d)
P = Schnorr.ser256_schnorr(P_point)
# s1
k1 = 78931426514357468882601520915645133116503184441831846482294115903507660427954
P1_point = Schnorr.multiply(k1)
if P1_point[1] % 2 != 0:
k1 = Schnorr.n - k1
P1_point = Schnorr.multiply(k1)
P1 = Schnorr.ser256_schnorr(P1_point)
s1_hex = BIP350.create_witness_locking_script(BIP350.encode_addr_bech32m(P1, "False"), "False")
s1_len_hex = ToolsUnit.calculate_varint(s1_hex)
tap_leaf_s1 = Schnorr.tagged_hash("TapLeaf", LEAF_VER + bytes.fromhex(s1_len_hex + s1_hex))
# s2
k2 = 53223457762164509281563914254149592059900713682793766747801624337469509007263
P2_point = Schnorr.multiply(k2)
if P2_point[1] % 2 != 0:
k2 = Schnorr.n - k2
P2_point = Schnorr.multiply(k2)
P2 = Schnorr.ser256_schnorr(P2_point)
s2_hex = BIP350.create_witness_locking_script(BIP350.encode_addr_bech32m(P2, "False"), "False")
s2_len_hex = ToolsUnit.calculate_varint(s2_hex)
tap_leaf_s2 = Schnorr.tagged_hash("TapLeaf", LEAF_VER + bytes.fromhex(s2_len_hex + s2_hex))
# s3
k3 = 48034867036800174573932088253129938072033279788016841632941291149515077395802
P3_point = Schnorr.multiply(k3)
if P3_point[1] % 2 != 0:
k3 = Schnorr.n - k3
P3_point = Schnorr.multiply(k3)
P3 = Schnorr.ser256_schnorr(P3_point)
s3_hex = BIP350.create_witness_locking_script(BIP350.encode_addr_bech32m(P3, "False"), "False")
s3_len_hex = ToolsUnit.calculate_varint(s3_hex)
tap_leaf_s3 = Schnorr.tagged_hash("TapLeaf", LEAF_VER + bytes.fromhex(s3_len_hex + s3_hex))
# tagged branch s1s2
tap_branch_s1s2 = Schnorr.tagged_hash("TapBranch", b''.join(sorted([tap_leaf_s1, tap_leaf_s2])))
# tagged branch s1s2s3
tap_branch_s1s2s3 = Schnorr.tagged_hash("TapBranch", b''.join(sorted([tap_branch_s1s2, tap_leaf_s3])))
# tap tweak t
t = Schnorr.tagged_hash("TapTweak", P + tap_branch_s1s2s3)
t_int = Schnorr.int_from_bytes(t)
# taproot pubkey Q = P + tG
Q_point = Schnorr.add(P_point, Schnorr.multiply(t_int))
Q = Schnorr.ser256_schnorr(Q_point)
# address_from
addr_from = BIP350.encode_addr_bech32m(Q, "False") # tb1pwwce3mqw3ry4pz3fnttf7ka3axcq8hq75scjnhgza32p70edw0wquvtr9w
# ----------
# I'll create a tx spending from addr_from to addr_to using script path S1
# ----------
# create addr_to
kto = 106223809955248159900714945014279058380174181497200169336538554075749085215638
Pto_point = Schnorr.multiply(kto)
if Pto_point[1] % 2 != 0:
kto = Schnorr.n - k1
Pto_point = Schnorr.multiply(kto)
Pto = Schnorr.ser256_schnorr(Pto_point)
addr_to = BIP350.encode_addr_bech32m(Pto, "False") # tb1pvhc33fd40y2vx2j8tx9hu338chxwpdy4s09lhm2mpmgee7mvwlkqd0cj2t
# data for the tx that sent me 0.00013710 BTC (taproot)
txid = "d6aabea35eb8b93882cecbe726c045f374a8ee0b1ba9c4422549441501d623e5"
txid_reverse = ToolsUnit.reverse_byte_order(txid)
vout = "00000000" # 0
amount_received = ToolsUnit.reverse_byte_order(hex(13710)[2:].rjust(16, "0")) # 13710 sats = 0.00013710 BTC
locking_script_input = BIP350.create_witness_locking_script(addr_from, "False")
len_locking_script_input = ToolsUnit.calculate_varint(locking_script_input)
# data for the tx I want to create
marker = "00"
flag = "01"
input_count = "01"
version = "01000000"
amount_to_send = ToolsUnit.reverse_byte_order(hex(13400)[2:].rjust(16, "0")) # 13400 sats = 0.00013400 BTC
sequence = "ffffffff"
output_count = "01"
locking_script_dest = BIP350.create_witness_locking_script(addr_to, "False")
len_locking_script_dest = ToolsUnit.calculate_varint(locking_script_dest)
locktime = "00000000"
sig_hash_type = "00000000" # SIGHASH_ALL_TAPROOT 00
sig_hash_type_1bytes = "00" # SIGHASH_ALL_TAPROOT 00
# ----------
# CONSTRUCTING SIGHASH x INPUT (taproot)
# ----------
hash_type = bytes.fromhex(sig_hash_type_1bytes)
nversion = bytes.fromhex(version)
nlocktime = bytes.fromhex(locktime)
# sha_prevouts (32) = SHA256(serialization of all input outpoints)
sha_prevouts = Schnorr.hash_sha256(bytes.fromhex(txid_reverse + vout))
# sha_amounts (32): the SHA256 of the serialization of all spent output amounts
sha_amounts = Schnorr.hash_sha256(bytes.fromhex(amount_received))
# sha_scriptpubkeys (32): the SHA256 of all spent outputs' scriptPubKeys, serialized as script inside CTxOut
sha_scriptpubkeys = Schnorr.hash_sha256(bytes.fromhex(len_locking_script_input + locking_script_input))
# sha_sequences (32): the SHA256 of the serialization of all input nSequence.
sha_sequences = Schnorr.hash_sha256(bytes.fromhex(sequence))
# sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
sha_outputs = Schnorr.hash_sha256(bytes.fromhex(amount_to_send + len_locking_script_dest + locking_script_dest))
# spend_type (1): equal to (ext_flag * 2) + annex_present, where annex_present is 0 if no annex is present,
# or 1 otherwise (the original witness stack has two or more witness elements,
# and the first byte of the last element is 0x50)
spend_type = bytes.fromhex("02") # script path -> ext_flag = 1
# input_index (4): index of this input in the transaction input vector. Index of the first input is 0
input_index = bytes.fromhex("00000000") # there is only 1 input in this tx I'm constructing
# We use SCRIPT PATH, so we have to add
# 1. tapleaf_hash of the script I am using to spend this UTXO
# 2. b'\x00' which is key_version, representing the current version of public keys in the
# tapscript signature opcode execution
# 3. codesep_pos = the opcode position of the last executed OP_CODESEPARATOR before the currently executed
# signature opcode, with the value in little endian (or 0xffffffff if none executed).
scrip_path_used = tap_leaf_s1 + b'\x00' + bytes.fromhex("ffffffff")
sig_to_hash = b'\x00' + hash_type + nversion + nlocktime + sha_prevouts + sha_amounts + sha_scriptpubkeys + sha_sequences\
+ sha_outputs + spend_type + input_index + scrip_path_used # first element is b'\x00' which is epoch 0
sighash = Schnorr.tagged_hash("TapSighash", sig_to_hash)
# ----------
# SIGNING w/ k1 - SCRIPT PATH -> S1
# ----------
sig = Schnorr.sign_schnorr(private_key_int=k1, msg_hash_bytes=sighash)
# ----------
# CONSTRUCTING WITNESS
# ----------
witness_count = "03" # [Stack element(s) satisfying TapScript_S1]
# [TapScript_S1]
# [Controlblock c]
r, s = sig
sig_hex = r.hex() + s.hex()
witness_sig_size = ToolsUnit.calculate_varint(sig_hex)
if Q_point[1] % 2 != 0:
parity_bit = b'\x01'
else:
parity_bit = b'\x00'
# control block:
# Its first byte stores the leaf version (#3) (top 7 bits) and the sign bit (#6) (bottom bit).
# The next 32 bytes store the (X coordinate only, because x-only key) of the internal public key (#4)
# Every block of 32 bytes after that encodes a component of the Merkle path (#5) connecting the leaf
# to the root (and then, the tweak), going in bottom-up direction.
control_block = bytes([LEAF_VER[0] + parity_bit[0]]) + P + tap_leaf_s2 + tap_leaf_s3
len_control_block = ToolsUnit.calculate_varint(control_block.hex())
witness = witness_count + witness_sig_size + sig_hex + s1_len_hex + s1_hex + len_control_block + control_block.hex()
# ----------
# TX READY
# ----------
tx = version + marker + flag + input_count + txid_reverse + vout + "00" + sequence\
+ output_count + amount_to_send + len_locking_script_dest + locking_script_dest\
+ witness + locktime
print(tx)
print("ESITO: NON FUNZIONA IN QUESTO MODO! LO STACK NON è VALIDO!")