2424 long = int
2525 _bchr = lambda x : bytes ([x ])
2626 _bord = lambda x : x
27+ from io import BytesIO as _BytesIO
28+ else :
29+ from cStringIO import StringIO as _BytesIO
2730
2831import struct
2932
3033import bitcoin .core
3134import bitcoin .core ._bignum
3235
36+ from .serialize import *
37+
3338MAX_SCRIPT_SIZE = 10000
3439MAX_SCRIPT_ELEMENT_SIZE = 520
3540MAX_SCRIPT_OPCODES = 201
@@ -672,6 +677,31 @@ def is_p2sh(self):
672677 _bord (self [1 ]) == 0x14 and
673678 _bord (self [22 ]) == OP_EQUAL )
674679
680+ def is_witness_scriptpubkey (self ):
681+ """Returns true if this is a scriptpubkey signaling segregated witness
682+ data. """
683+ return 3 <= len (self ) <= 42 and CScriptOp (struct .unpack ('<b' ,self [0 ])[0 ]).is_small_int ()
684+
685+ def witness_version (self ):
686+ """Returns the witness version on [0,16]. """
687+ return next (iter (self ))
688+
689+ def is_witness_v0_keyhash (self ):
690+ """Returns true if this is a scriptpubkey for V0 P2WPKH. """
691+ return len (self ) == 22 and self [0 :2 ] == b'\x00 \x14 '
692+
693+ def is_witness_v0_nested_keyhash (self ):
694+ """Returns true if this is a scriptpubkey for V0 P2WPKH embedded in P2SH. """
695+ return len (self ) == 23 and self [0 :3 ] == b'\x16 \x00 \x14 '
696+
697+ def is_witness_v0_scripthash (self ):
698+ """Returns true if this is a scriptpubkey for V0 P2WSH. """
699+ return len (self ) == 34 and self [0 :2 ] == b'\x00 \x20 '
700+
701+ def is_witness_v0_nested_scripthash (self ):
702+ """Returns true if this is a scriptpubkey for V0 P2WSH embedded in P2SH. """
703+ return len (self ) == 23 and self [0 :2 ] == b'\xa9 \x14 ' and self [- 1 ] == b'\x87 '
704+
675705 def is_push_only (self ):
676706 """Test if the script only contains pushdata ops
677707
@@ -773,6 +803,38 @@ def GetSigOpCount(self, fAccurate):
773803 lastOpcode = opcode
774804 return n
775805
806+ class CScriptWitness (ImmutableSerializable ):
807+ """An encoding of the data elements on the initial stack for (segregated
808+ witness)
809+ """
810+ __slots__ = ['stack' ]
811+
812+ def __init__ (self , stack = ()):
813+ object .__setattr__ (self , 'stack' , stack )
814+
815+ def __len__ (self ):
816+ return len (self .stack )
817+
818+ def __iter__ (self ):
819+ return iter (self .stack )
820+
821+ def __repr__ (self ):
822+ return 'CScriptWitness(' + ',' .join ("x('%s')" % bitcoin .core .b2x (s ) for s in self .stack ) + ')'
823+
824+ def is_null (self ):
825+ return len (self .stack ) == 0
826+
827+ @classmethod
828+ def stream_deserialize (cls , f ):
829+ n = VarIntSerializer .stream_deserialize (f )
830+ stack = tuple (BytesSerializer .stream_deserialize (f ) for i in range (n ))
831+ return cls (stack )
832+
833+ def stream_serialize (self , f ):
834+ VarIntSerializer .stream_serialize (len (self .stack ), f )
835+ for s in self .stack :
836+ BytesSerializer .stream_serialize (s , f )
837+
776838
777839SIGHASH_ALL = 1
778840SIGHASH_NONE = 2
@@ -894,21 +956,71 @@ def RawSignatureHash(script, txTo, inIdx, hashtype):
894956 txtmp .vin = []
895957 txtmp .vin .append (tmp )
896958
959+ txtmp .wit = bitcoin .core .CTxWitness ()
897960 s = txtmp .serialize ()
898- s += struct .pack (b"<I " , hashtype )
961+ s += struct .pack (b"<i " , hashtype )
899962
900963 hash = bitcoin .core .Hash (s )
901964
902965 return (hash , None )
903966
967+ SIGVERSION_BASE = 0
968+ SIGVERSION_WITNESS_V0 = 1
904969
905- def SignatureHash (script , txTo , inIdx , hashtype ):
970+ def SignatureHash (script , txTo , inIdx , hashtype , amount = None , sigversion = SIGVERSION_BASE ):
906971 """Calculate a signature hash
907972
908973 'Cooked' version that checks if inIdx is out of bounds - this is *not*
909974 consensus-correct behavior, but is what you probably want for general
910975 wallet use.
911976 """
977+
978+ if sigversion == SIGVERSION_WITNESS_V0 :
979+ hashPrevouts = b'\x00 ' * 32
980+ hashSequence = b'\x00 ' * 32
981+ hashOutputs = b'\x00 ' * 32
982+
983+ if not (hashtype & SIGHASH_ANYONECANPAY ):
984+ serialize_prevouts = bytes ()
985+ for i in txTo .vin :
986+ serialize_prevouts += i .prevout .serialize ()
987+ hashPrevouts = bitcoin .core .Hash (serialize_prevouts )
988+
989+ if (not (hashtype & SIGHASH_ANYONECANPAY ) and (hashtype & 0x1f ) != SIGHASH_SINGLE and (hashtype & 0x1f ) != SIGHASH_NONE ):
990+ serialize_sequence = bytes ()
991+ for i in txTo .vin :
992+ serialize_sequence += struct .pack ("<I" , i .nSequence )
993+ hashSequence = bitcoin .core .Hash (serialize_sequence )
994+
995+ if ((hashtype & 0x1f ) != SIGHASH_SINGLE and (hashtype & 0x1f ) != SIGHASH_NONE ):
996+ serialize_outputs = bytes ()
997+ for o in txTo .vout :
998+ serialize_outputs += o .serialize ()
999+ hashOutputs = bitcoin .core .Hash (serialize_outputs )
1000+ elif ((hashtype & 0x1f ) == SIGHASH_SINGLE and inIdx < len (txTo .vout )):
1001+ serialize_outputs = txTo .vout [inIdx ].serialize ()
1002+ hashOutputs = bitcoin .core .Hash (serialize_outputs )
1003+
1004+ f = _BytesIO ()
1005+ f .write (struct .pack ("<i" , txTo .nVersion ))
1006+ f .write (hashPrevouts )
1007+ f .write (hashSequence )
1008+ txTo .vin [inIdx ].prevout .stream_serialize (f )
1009+ BytesSerializer .stream_serialize (script , f )
1010+ f .write (struct .pack ("<q" , amount ))
1011+ f .write (struct .pack ("<I" , txTo .vin [inIdx ].nSequence ))
1012+ f .write (hashOutputs )
1013+ f .write (struct .pack ("<i" , txTo .nLockTime ))
1014+ f .write (struct .pack ("<i" , hashtype ))
1015+
1016+ return bitcoin .core .Hash (f .getvalue ())
1017+
1018+ if script .is_witness_scriptpubkey ():
1019+ print ("WARNING: You seem to be attempting to sign a scriptPubKey from an" )
1020+ print ("WARNING: output with segregated witness. This is NOT the correct" )
1021+ print ("WARNING: thing to sign. You should pass SignatureHash the corresponding" )
1022+ print ("WARNING: P2WPKH or P2WSH script instead." )
1023+
9121024 (h , err ) = RawSignatureHash (script , txTo , inIdx , hashtype )
9131025 if err is not None :
9141026 raise ValueError (err )
@@ -1048,6 +1160,7 @@ def SignatureHash(script, txTo, inIdx, hashtype):
10481160 'CScriptInvalidError' ,
10491161 'CScriptTruncatedPushDataError' ,
10501162 'CScript' ,
1163+ 'CScriptWitness' ,
10511164 'SIGHASH_ALL' ,
10521165 'SIGHASH_NONE' ,
10531166 'SIGHASH_SINGLE' ,
@@ -1056,4 +1169,7 @@ def SignatureHash(script, txTo, inIdx, hashtype):
10561169 'RawSignatureHash' ,
10571170 'SignatureHash' ,
10581171 'IsLowDERSignature' ,
1172+
1173+ 'SIGVERSION_BASE' ,
1174+ 'SIGVERSION_WITNESS_V0' ,
10591175)
0 commit comments