def _hash_outputs(self, index, sighash_type): '''BIP143 hashOutputs implementation Args: index (int): index of input being signed sighash_type (int): SIGHASH_SINGLE or SIGHASH_ALL Returns: (bytes): the hashOutputs, a 32 byte hash ''' if sighash_type == shared.SIGHASH_ALL: # If the sighash type is ALL, # hashOutputs is the double SHA256 of all output amounts # paired up with their scriptPubKey; outputs = ByteData() for tx_out in self.tx_outs: outputs += tx_out.to_bytes() return utils.hash256(outputs.to_bytes()) elif (sighash_type == shared.SIGHASH_SINGLE and index < len(self.tx_outs)): # if sighash type is SINGLE # and the input index is smaller than the number of outputs, # hashOutputs is the double SHA256 of the output at the same index return utils.hash256(self.tx_outs[index].to_bytes()) else: # Otherwise, hashOutputs is a uint256 of 0x0000......0000 raise NotImplementedError( 'I refuse to implement the SIGHASH_SINGLE bug.')
def _sighash_final_hashing(self, copy_tx, sighash_type): ''' Tx, int -> bytes Returns the hash that should be signed https://en.bitcoin.it/wiki/OP_CHECKSIG#Procedure_for_Hashtype_SIGHASH_ANYONECANPAY ''' sighash = ByteData() sighash += copy_tx.to_bytes() sighash += utils.i2le_padded(sighash_type, 4) return utils.hash256(sighash.to_bytes())
def _hash_prevouts(self, anyone_can_pay): if anyone_can_pay: # If the ANYONECANPAY flag is set, # hashPrevouts is a uint256 of 0x0000......0000. hash_prevouts = b'\x00' * 32 else: # hashPrevouts is the double SHA256 of all outpoints; outpoints = ByteData() for tx_in in self.tx_ins: outpoints += tx_in.outpoint hash_prevouts = utils.hash256(outpoints.to_bytes()) return hash_prevouts
def segwit_sighash(self, index: int, sighash_type: int, prevout_value: bytes, script: bytes, anyone_can_pay: bool = False) -> bytes: ''' Implements bip143 (witness) sighash. Prefer calling `sighash_all` or `sighash_single`. For documentation see here: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki For an excellent pasta dinner, see here: https://ricette.giallozafferano.it/Spaghetti-alla-Norma.html ''' data = ByteData() # 1. nVersion of the transaction (4-byte little endian) data += self.version # 2. hashPrevouts (32-byte hash) data += self._hash_prevouts(anyone_can_pay=anyone_can_pay) # 3. hashSequence (32-byte hash) data += self._hash_sequence(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) # 4. outpoint (32-byte hash + 4-byte little endian) data += self.tx_ins[index].outpoint # 5. scriptCode of the input (serialized as scripts inside CTxOuts) data += script # 6. value of the output spent by this input (8-byte little endian) data += prevout_value # 7. nSequence of the input (4-byte little endian) data += self.tx_ins[index].sequence # 8. hashOutputs (32-byte hash) data += self._hash_outputs(index=index, sighash_type=sighash_type) # 9. nLocktime of the transaction (4-byte little endian) data += self.lock_time # 10. sighash type of the signature (4-byte little endian) data += self._segwit_sighash_adjustment(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) return utils.hash256(data.to_bytes())
def _sighash_forkid( self, index: int, script: bytes, prevout_value: bytes, sighash_type: int, anyone_can_pay: bool = False): ''' Tx, int, byte-like, byte-like, int, bool -> bytes https://github.com/bitcoincashorg/spec/blob/master/replay-protected-sighash.md ''' self.validate_bytes(prevout_value, 8) data = ByteData() # 1. nVersion of the transaction (4-byte little endian) data += self.version # 2. hashPrevouts (32-byte hash) data += self._hash_prevouts(anyone_can_pay=anyone_can_pay) # 3. hashSequence (32-byte hash) data += self._hash_sequence(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) # 4. outpoint (32-byte hash + 4-byte little endian) data += self.tx_ins[index].outpoint # 5. scriptCode of the input (serialized as scripts inside CTxOuts) data += script # 6. value of the output spent by this input (8-byte little endian) data += prevout_value # 7. nSequence of the input (4-byte little endian) data += self.tx_ins[index].sequence # 8. hashOutputs (32-byte hash) data += self._hash_outputs(index=index, sighash_type=sighash_type) # 9. nLocktime of the transaction (4-byte little endian) data += self.lock_time # 10. sighash type of the signature (4-byte little endian) data += self._forkid_sighash_adjustment(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) return utils.hash256(data.to_bytes())
def segwit_sighash(self, index, script, prevout_value=None, sighash_type=None, anyone_can_pay=False): ''' this function sets up sighash in BIP143 style https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki https://ricette.giallozafferano.it/Spaghetti-alla-Norma.html ''' data = ByteData() # 1. nVersion of the transaction (4-byte little endian) data += self.version # 2. hashPrevouts (32-byte hash) data += self._hash_prevouts(anyone_can_pay=anyone_can_pay) # 3. hashSequence (32-byte hash) data += self._hash_sequence(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) # 4. outpoint (32-byte hash + 4-byte little endian) data += self.tx_ins[index].outpoint # 5. scriptCode of the input (serialized as scripts inside CTxOuts) data += self._adjusted_script_code(script=script) # 6. value of the output spent by this input (8-byte little endian) data += prevout_value # 7. nSequence of the input (4-byte little endian) data += self.tx_ins[index].sequence # 8. hashOutputs (32-byte hash) data += self._hash_outputs(index=index, sighash_type=sighash_type) # 9. nLocktime of the transaction (4-byte little endian) data += self.lock_time # 10. sighash type of the signature (4-byte little endian) data += self._segwit_sighash_adjustment(sighash_type=sighash_type, anyone_can_pay=anyone_can_pay) return utils.hash256(data.to_bytes())
def _hash_sequence(self, sighash_type, anyone_can_pay): '''BIP143 hashSequence implementation Args: sighash_type (int): SIGHASH_SINGLE or SIGHASH_ALL anyone_can_pay (bool): true if ANYONECANPAY should be set Returns: (bytes): the hashSequence, a 32 byte hash ''' if anyone_can_pay or sighash_type == shared.SIGHASH_SINGLE: # If any of ANYONECANPAY, SINGLE sighash type is set, # hashSequence is a uint256 of 0x0000......0000. return b'\x00' * 32 else: # hashSequence is the double SHA256 of nSequence of all inputs; sequences = ByteData() for tx_in in self.tx_ins: sequences += tx_in.sequence return utils.hash256(sequences.to_bytes())