Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    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)