def sighash_single(self, index, script=None, anyone_can_pay=False): ''' https://github.com/decred/dcrd/blob/master/txscript/script.go ''' copy_tx = self._sighash_prep(index=index, script=script) try: copy_tx_outs = copy_tx.tx_outs[:index + 1] copy_tx_outs = [ TxOut(value=b'\xff' * 8, output_script=b'') for _ in copy_tx.tx_ins ] copy_tx_outs[index] = copy_tx.tx_outs[index] except IndexError: raise NotImplementedError( 'I refuse to implement the SIGHASH_SINGLE bug.') copy_tx_ins = [ tx_in.copy(sequence=b'\x00\x00\x00\x00') for tx_in in copy_tx.tx_ins ] copy_tx_ins[index] = copy_tx.tx_ins[index] copy_tx = copy_tx.copy(tx_ins=copy_tx_ins, tx_outs=copy_tx_outs) if anyone_can_pay: return self._sighash_anyone_can_pay( index=index, copy_tx=copy_tx, sighash_type=shared.SIGHASH_SINGLE) return self._sighash_final_hashing(index=index, copy_tx=copy_tx, sighash_type=shared.SIGHASH_SINGLE)
def sighash_single(self, index=0, script=None, prevout_value=None, anyone_can_pay=False): ''' SproutTx, int, byte-like, byte-like, bool -> bytearray Sighashes suck Generates the hash to be signed with SIGHASH_SINGLE https://en.bitcoin.it/wiki/OP_CHECKSIG#Procedure_for_Hashtype_SIGHASH_SINGLE https://bitcoin.stackexchange.com/questions/3890/for-sighash-single-do-the-outputs-other-than-at-the-input-index-have-8-bytes-or https://github.com/petertodd/python-bitcoinlib/blob/051ec4e28c1f6404fd46713c2810d4ebbed38de4/bitcoin/core/script.py#L913-L965 ''' if self.tx_joinsplits is not None: raise ValueError('Sighash single not permitted with joinsplits.') if index >= len(self.tx_outs): raise NotImplementedError( 'I refuse to implement the SIGHASH_SINGLE bug.') if riemann.network.FORKID is not None: return self._sighash_forkid(index=index, script=script, prevout_value=prevout_value, sighash_type=shared.SIGHASH_SINGLE, anyone_can_pay=anyone_can_pay) copy_tx = self._sighash_prep(index=index, script=script) # Remove outputs after the one we're signing # Other tx_outs are set to -1 value and null scripts copy_tx_outs = copy_tx.tx_outs[:index + 1] copy_tx_outs = [ TxOut(value=b'\xff' * 8, output_script=b'') for _ in copy_tx.tx_ins ] # Null them all copy_tx_outs[index] = copy_tx.tx_outs[index] # Fix the current one # Other tx_ins sequence numbers are set to 0 copy_tx_ins = [ tx_in.copy(sequence=b'\x00\x00\x00\x00') for tx_in in copy_tx.tx_ins ] # Set all to 0 copy_tx_ins[index] = copy_tx.tx_ins[index] # Fix the current one copy_tx = copy_tx.copy(tx_ins=copy_tx_ins, tx_outs=copy_tx_outs) if anyone_can_pay: # Forward onwards return self._sighash_anyone_can_pay(index, copy_tx, shared.SIGHASH_SINGLE) return self._sighash_final_hashing(copy_tx, shared.SIGHASH_SINGLE)
def from_bytes(SproutTx, byte_string): ''' byte-like -> SproutTx ''' version = byte_string[0:4] tx_ins = [] tx_ins_num = shared.VarInt.from_bytes(byte_string[4:]) current = 4 + len(tx_ins_num) for _ in range(tx_ins_num.number): tx_in = TxIn.from_bytes(byte_string[current:]) current += len(tx_in) tx_ins.append(tx_in) tx_outs = [] tx_outs_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_outs_num) for _ in range(tx_outs_num.number): tx_out = TxOut.from_bytes(byte_string[current:]) current += len(tx_out) tx_outs.append(tx_out) lock_time = byte_string[current:current + 4] current += 4 tx_joinsplits = None joinsplit_pubkey = None joinsplit_sig = None if utils.le2i(version) == 2: # If we expect joinsplits tx_joinsplits = [] tx_joinsplits_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_joinsplits_num) for _ in range(tx_joinsplits_num.number): joinsplit = z.SproutJoinsplit.from_bytes(byte_string[current:]) current += len(joinsplit) tx_joinsplits.append(joinsplit) joinsplit_pubkey = byte_string[current:current + 32] current += 32 joinsplit_sig = byte_string[current:current + 64] return SproutTx(version=version, tx_ins=tx_ins, tx_outs=tx_outs, lock_time=lock_time, tx_joinsplits=tx_joinsplits, joinsplit_pubkey=joinsplit_pubkey, joinsplit_sig=joinsplit_sig)
def from_bytes(SaplingTx, byte_string): ''' byte-like -> SaplingTx ''' header = byte_string[0:4] group_id = byte_string[4:8] if header != b'\x04\x00\x00\x80' or group_id != b'\x85\x20\x2f\x89': raise ValueError( 'Bad header or group ID. Expected {} and {}. Got: {} and {}' .format(b'\x04\x00\x00\x80'.hex(), b'\x85\x20\x2f\x89'.hex(), header.hex(), group_id.hex())) tx_ins = [] tx_ins_num = shared.VarInt.from_bytes(byte_string[8:]) current = 8 + len(tx_ins_num) for _ in range(tx_ins_num.number): tx_in = TxIn.from_bytes(byte_string[current:]) current += len(tx_in) tx_ins.append(tx_in) tx_outs = [] tx_outs_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_outs_num) for _ in range(tx_outs_num.number): tx_out = TxOut.from_bytes(byte_string[current:]) current += len(tx_out) tx_outs.append(tx_out) lock_time = byte_string[current:current + 4] current += 4 expiry_height = byte_string[current:current + 4] current += 4 value_balance = byte_string[current:current + 8] current += 8 tx_shielded_spends = [] shielded_spends_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(shielded_spends_num) for _ in range(shielded_spends_num.number): ss = SaplingShieldedSpend.from_bytes(byte_string[current:]) current += len(ss) tx_shielded_spends.append(ss) tx_shielded_outputs = [] shielded_outputs_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(shielded_outputs_num) for _ in range(shielded_outputs_num.number): so = SaplingShieldedOutput.from_bytes(byte_string[current:]) current += len(so) tx_shielded_outputs.append(so) tx_joinsplits = [] tx_joinsplits_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_outs_num) for _ in range(tx_joinsplits_num.number): tx_joinsplit = SaplingJoinsplit.from_bytes( byte_string[current:]) current += len(tx_joinsplit) tx_joinsplits.append(tx_joinsplit) if len(tx_joinsplits) > 0: joinsplit_pubkey = byte_string[current:current + 32] current += 32 joinsplit_sig = byte_string[current:current + 64] current += 64 else: joinsplit_pubkey = None joinsplit_sig = None if len(tx_shielded_spends) + len(tx_shielded_outputs) > 0: binding_sig = byte_string[current:current + 64] current += 64 else: binding_sig = None return SaplingTx( tx_ins=tx_ins, tx_outs=tx_outs, lock_time=lock_time, expiry_height=expiry_height, value_balance=value_balance, tx_shielded_spends=tx_shielded_spends, tx_shielded_outputs=tx_shielded_outputs, tx_joinsplits=tx_joinsplits, joinsplit_pubkey=joinsplit_pubkey, joinsplit_sig=joinsplit_sig, binding_sig=binding_sig)
def from_bytes(OverwinterTx, byte_string): ''' byte-like -> OverwinterTx ''' header = byte_string[0:4] group_id = byte_string[4:8] if header != b'\x03\x00\x00\x80' or group_id != b'\x70\x82\xc4\x03': raise ValueError( 'Bad header or group ID. Expected {} and {}. Got: {} and {}' .format(b'\x03\x00\x00\x80'.hex(), b'\x70\x82\xc4\x03'.hex(), header.hex(), group_id.hex())) tx_ins = [] tx_ins_num = shared.VarInt.from_bytes(byte_string[8:]) current = 8 + len(tx_ins_num) for _ in range(tx_ins_num.number): tx_in = TxIn.from_bytes(byte_string[current:]) current += len(tx_in) tx_ins.append(tx_in) tx_outs = [] tx_outs_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_outs_num) for _ in range(tx_outs_num.number): tx_out = TxOut.from_bytes(byte_string[current:]) current += len(tx_out) tx_outs.append(tx_out) lock_time = byte_string[current:current + 4] current += 4 expiry_height = byte_string[current:current + 4] current += 4 if current == len(byte_string): # No joinsplits tx_joinsplits = tuple() joinsplit_pubkey = None joinsplit_sig = None else: tx_joinsplits = [] tx_joinsplits_num = shared.VarInt.from_bytes(byte_string[current:]) current += len(tx_outs_num) for _ in range(tx_joinsplits_num.number): tx_joinsplit = z.SproutJoinsplit.from_bytes( byte_string[current:]) current += len(tx_joinsplit) tx_joinsplits.append(tx_joinsplit) joinsplit_pubkey = byte_string[current:current + 32] current += 32 joinsplit_sig = byte_string[current:current + 64] return OverwinterTx( tx_ins=tx_ins, tx_outs=tx_outs, lock_time=lock_time, expiry_height=expiry_height, tx_joinsplits=tx_joinsplits, joinsplit_pubkey=joinsplit_pubkey, joinsplit_sig=joinsplit_sig)