1+ import abc
12import json
23import pabtc .core
34import pabtc .denomination
@@ -110,12 +111,29 @@ def unspent(self, addr: str) -> typing.List[Utxo]:
110111 raise Exception ('unreachable' )
111112
112113
113- class Tp2pkh :
114+ class Signer (abc .ABC ):
115+ # Signer provides the functionality to sign a transaction.
116+
117+ @abc .abstractmethod
118+ def __init__ (self ) -> None :
119+ self .script : bytearray
120+ self .addr : str
121+
122+ def json (self ) -> typing .Dict :
123+ return {}
124+
125+ @abc .abstractmethod
126+ def sign (self , tx : pabtc .core .Transaction ) -> None :
127+ # Sign the transaction in place.
128+ pass
129+
130+
131+ class Signerp2pkh (Signer ):
114132 def __init__ (self , prikey : int ) -> None :
115133 self .prikey = pabtc .core .PriKey (prikey )
116134 self .pubkey = self .prikey .pubkey ()
135+ self .script = pabtc .core .ScriptPubKey .p2pkh (self .pubkey .hash ())
117136 self .addr = pabtc .core .Address .p2pkh (self .pubkey .hash ())
118- self .script = pabtc .core .ScriptPubKey .address (self .addr )
119137
120138 def __repr__ (self ) -> str :
121139 return json .dumps (self .json ())
@@ -124,30 +142,26 @@ def json(self) -> typing.Dict:
124142 return {
125143 'prikey' : self .prikey .json (),
126144 'pubkey' : self .pubkey .json (),
127- 'addr' : self .addr ,
128145 'script' : self .script .hex (),
146+ 'addr' : self .addr ,
129147 }
130148
131149 def sign (self , tx : pabtc .core .Transaction ) -> None :
132150 for i , e in enumerate (tx .vin ):
133- m = tx .digest_legacy (i , pabtc .core .sighash_all , e . out_point . load (). script_pubkey )
151+ m = tx .digest_legacy (i , pabtc .core .sighash_all , self . script )
134152 s = self .prikey .sign_ecdsa_der (m )
135153 s .append (pabtc .core .sighash_all )
136154 e .script_sig = pabtc .core .ScriptSig .p2pkh (s , self .pubkey )
137155
138- def txin (self , op : pabtc .core .OutPoint ) -> pabtc .core .TxIn :
139- return pabtc .core .TxIn (op , bytearray (107 ), 0xffffffff , [])
140-
141156
142- class Tp2shp2ms :
143- # Multi-signature: See https://en.bitcoin.it/wiki/Multi-signature.
144- def __init__ (self , m : int , pubkey : typing .List [pabtc .core .PubKey ], prikey : typing .List [int ]) -> None :
145- self .m = m
157+ class Signerp2shp2ms (Signer ):
158+ def __init__ (self , pubkey : typing .List [pabtc .core .PubKey ], prikey : typing .List [int ]) -> None :
146159 self .prikey = [pabtc .core .PriKey (e ) for e in prikey ]
147160 self .pubkey = pubkey
148- self .redeem = pabtc .core .ScriptPubKey .p2ms (self .m , pubkey )
149- self .addr = pabtc .core .Address .p2sh (pabtc .core .hash160 (self .redeem ))
150- self .script = pabtc .core .ScriptPubKey .address (self .addr )
161+ self .redeem = pabtc .core .ScriptPubKey .p2ms (len (prikey ), pubkey )
162+ self .redeem_hash = pabtc .core .hash160 (self .redeem )
163+ self .script = pabtc .core .ScriptPubKey .p2sh (self .redeem_hash )
164+ self .addr = pabtc .core .Address .p2sh (self .redeem_hash )
151165
152166 def __repr__ (self ) -> str :
153167 return json .dumps (self .json ())
@@ -156,8 +170,9 @@ def json(self) -> typing.Dict:
156170 return {
157171 'prikey' : [e .json () for e in self .prikey ],
158172 'pubkey' : [e .json () for e in self .pubkey ],
159- 'addr ' : self .addr ,
173+ 'redeem ' : self .redeem . hex () ,
160174 'script' : self .script .hex (),
175+ 'addr' : self .addr ,
161176 }
162177
163178 def sign (self , tx : pabtc .core .Transaction ) -> None :
@@ -167,19 +182,15 @@ def sign(self, tx: pabtc.core.Transaction) -> None:
167182 s = prikey .sign_ecdsa_der (tx .digest_legacy (i , pabtc .core .sighash_all , self .redeem ))
168183 s .append (pabtc .core .sighash_all )
169184 sig .append (s )
170- e .script_sig = pabtc .core .ScriptSig .p2sh_p2ms (sig , self .m , self .pubkey )
171-
172- def txin (self , op : pabtc .core .OutPoint ) -> pabtc .core .TxIn :
173- script_sig = pabtc .core .ScriptSig .p2sh_p2ms ([bytearray (72 )] * len (self .prikey ), self .m , self .pubkey )
174- return pabtc .core .TxIn (op , script_sig , 0xffffffff , [])
185+ e .script_sig = pabtc .core .ScriptSig .p2sh_p2ms (sig , len (self .prikey ), self .pubkey )
175186
176187
177- class Tp2shp2wpkh :
188+ class Signerp2shp2wpkh ( Signer ) :
178189 def __init__ (self , prikey : int ) -> None :
179190 self .prikey = pabtc .core .PriKey (prikey )
180191 self .pubkey = self .prikey .pubkey ()
192+ self .script = pabtc .core .ScriptPubKey .p2sh_p2wpkh (self .pubkey .hash ())
181193 self .addr = pabtc .core .Address .p2sh_p2wpkh (self .pubkey .hash ())
182- self .script = pabtc .core .ScriptPubKey .address (self .addr )
183194
184195 def __repr__ (self ) -> str :
185196 return json .dumps (self .json ())
@@ -188,32 +199,26 @@ def json(self) -> typing.Dict:
188199 return {
189200 'prikey' : self .prikey .json (),
190201 'pubkey' : self .pubkey .json (),
191- 'addr' : self .addr ,
192202 'script' : self .script .hex (),
203+ 'addr' : self .addr ,
193204 }
194205
195206 def sign (self , tx : pabtc .core .Transaction ) -> None :
196207 # See: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh
197- pubkey_hash = pabtc .core .hash160 (self .pubkey .sec ())
198- script_code = pabtc .core .ScriptPubKey .p2pkh (pubkey_hash )
199- script_sig = pabtc .core .ScriptSig .p2sh_p2wpkh (self .pubkey .hash ())
200208 for i , e in enumerate (tx .vin ):
201- e .script_sig = script_sig
202- s = self .prikey .sign_ecdsa_der (tx .digest_segwit_v0 (i , pabtc .core .sighash_all , script_code ))
209+ e .script_sig = pabtc .core .ScriptSig .p2sh_p2wpkh (self .pubkey .hash ())
210+ m = tx .digest_segwit_v0 (i , pabtc .core .sighash_all , pabtc .core .ScriptPubKey .p2pkh (self .pubkey .hash ()))
211+ s = self .prikey .sign_ecdsa_der (m )
203212 s .append (pabtc .core .sighash_all )
204- e .witness [0 ] = s
205- e .witness [1 ] = self .pubkey .sec ()
206-
207- def txin (self , op : pabtc .core .OutPoint ) -> pabtc .core .TxIn :
208- return pabtc .core .TxIn (op , bytearray (23 ), 0xffffffff , [bytearray (72 ), bytearray (33 )])
213+ e .witness = [s , self .pubkey .sec ()]
209214
210215
211- class Tp2wpkh :
216+ class Signerp2wpkh ( Signer ) :
212217 def __init__ (self , prikey : int ) -> None :
213218 self .prikey = pabtc .core .PriKey (prikey )
214219 self .pubkey = self .prikey .pubkey ()
220+ self .script = pabtc .core .ScriptPubKey .p2wpkh (self .pubkey .hash ())
215221 self .addr = pabtc .core .Address .p2wpkh (self .pubkey .hash ())
216- self .script = pabtc .core .ScriptPubKey .address (self .addr )
217222
218223 def __repr__ (self ) -> str :
219224 return json .dumps (self .json ())
@@ -222,32 +227,28 @@ def json(self) -> typing.Dict:
222227 return {
223228 'prikey' : self .prikey .json (),
224229 'pubkey' : self .pubkey .json (),
225- 'addr' : self .addr ,
226230 'script' : self .script .hex (),
231+ 'addr' : self .addr ,
227232 }
228233
229234 def sign (self , tx : pabtc .core .Transaction ) -> None :
230235 # See: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh
231- pubkey_hash = pabtc .core .hash160 (self .pubkey .sec ())
232- script_code = pabtc .core .ScriptPubKey .p2pkh (pubkey_hash )
233236 for i , e in enumerate (tx .vin ):
234- s = self .prikey .sign_ecdsa_der (tx .digest_segwit_v0 (i , pabtc .core .sighash_all , script_code ))
237+ m = tx .digest_segwit_v0 (i , pabtc .core .sighash_all , pabtc .core .ScriptPubKey .p2pkh (self .pubkey .hash ()))
238+ s = self .prikey .sign_ecdsa_der (m )
235239 s .append (pabtc .core .sighash_all )
236- e .witness [0 ] = s
237- e .witness [1 ] = self .pubkey .sec ()
238-
239- def txin (self , op : pabtc .core .OutPoint ) -> pabtc .core .TxIn :
240- return pabtc .core .TxIn (op , bytearray (), 0xffffffff , [bytearray (72 ), bytearray (33 )])
240+ e .witness = [s , self .pubkey .sec ()]
241241
242242
243- class Tp2tr :
244- def __init__ (self , prikey : int , root : bytearray ) -> None :
243+ class Signerp2tr ( Signer ) :
244+ def __init__ (self , prikey : int , merkle : bytearray ) -> None :
245245 self .prikey = pabtc .core .PriKey (prikey )
246246 self .pubkey = self .prikey .pubkey ()
247- p2tr_pubkey = bytearray (pabtc .taproot .pubkey_tweak (self .pubkey .pt (), root ).x .n .to_bytes (32 ))
248- self .addr = pabtc .core .Address .p2tr (p2tr_pubkey )
249- self .root = root
250- self .script = pabtc .core .ScriptPubKey .address (self .addr )
247+ self .merkle = merkle
248+ self .prikey_tweak = pabtc .core .PriKey .fr_decode (pabtc .taproot .prikey_tweak (self .prikey .fr (), self .merkle ))
249+ self .pubkey_tweak = pabtc .core .PubKey .pt_decode (pabtc .taproot .pubkey_tweak (self .pubkey .pt (), merkle ))
250+ self .script = pabtc .core .ScriptPubKey .p2tr (bytearray (self .pubkey_tweak .x .to_bytes (32 )))
251+ self .addr = pabtc .core .Address .p2tr (bytearray (self .pubkey_tweak .x .to_bytes (32 )))
251252
252253 def __repr__ (self ) -> str :
253254 return json .dumps (self .json ())
@@ -256,32 +257,25 @@ def json(self) -> typing.Dict:
256257 return {
257258 'prikey' : self .prikey .json (),
258259 'pubkey' : self .pubkey .json (),
259- 'addr' : self .addr ,
260- 'root' : self .root .hex (),
260+ 'merkle' : self .merkle .hex (),
261261 'script' : self .script .hex (),
262+ 'addr' : self .addr ,
262263 }
263264
264265 def sign (self , tx : pabtc .core .Transaction ) -> None :
265266 # See: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
266- prikey = pabtc .core .PriKey .fr_decode (pabtc .taproot .prikey_tweak (self .prikey .fr (), self .root ))
267267 for i , e in enumerate (tx .vin ):
268268 m = tx .digest_segwit_v1 (i , pabtc .core .sighash_all , bytearray ())
269- s = prikey .sign_schnorr (m ) + bytearray ([pabtc .core .sighash_all ])
270- e .witness [0 ] = s
271-
272- def txin (self , op : pabtc .core .OutPoint ) -> pabtc .core .TxIn :
273- return pabtc .core .TxIn (op , bytearray (), 0xffffffff , [bytearray (65 )])
274-
275-
276- T = Tp2pkh | Tp2shp2ms | Tp2shp2wpkh | Tp2wpkh | Tp2tr | typing .Any
269+ s = self .prikey_tweak .sign_schnorr (m ) + bytearray ([pabtc .core .sighash_all ])
270+ e .witness = [s ]
277271
278272
279273class Wallet :
280- def __init__ (self , signer : T ) -> None :
274+ def __init__ (self , signer : Signer ) -> None :
281275 self .signer = signer
282- self .addr = self .signer .addr
283276 self .script = self .signer .script
284277 self .search = Searcher ()
278+ self .addr = self .signer .addr
285279
286280 def __repr__ (self ) -> str :
287281 return json .dumps (self .json ())
@@ -304,7 +298,7 @@ def transfer(self, script: bytearray, value: int) -> bytearray:
304298 tx .vout .append (pabtc .core .TxOut (accept_value , accept_script ))
305299 tx .vout .append (pabtc .core .TxOut (change_value , change_script ))
306300 for utxo in self .unspent ():
307- txin = self . signer . txin (utxo .out_point )
301+ txin = pabtc . core . TxIn (utxo .out_point , bytearray (), 0xffffffff , [] )
308302 tx .vin .append (txin )
309303 sender_value += utxo .out .value
310304 change_value = sender_value - accept_value - tx .vbytes () * fr
@@ -328,7 +322,7 @@ def transfer_all(self, script: bytearray) -> bytearray:
328322 tx = pabtc .core .Transaction (2 , [], [], 0 )
329323 tx .vout .append (pabtc .core .TxOut (accept_value , accept_script ))
330324 for utxo in self .unspent ():
331- txin = self . signer . txin (utxo .out_point )
325+ txin = pabtc . core . TxIn (utxo .out_point , bytearray (), 0xffffffff , [] )
332326 tx .vin .append (txin )
333327 sender_value += utxo .out .value
334328 accept_value = sender_value - tx .vbytes () * fr
0 commit comments