Exemplo n.º 1
0
async def process_unknown_action(ctx: wire.Context, w: Writer,
                                 action: EosTxActionAck) -> None:
    checksum = HashWriter(sha256())
    writers.write_variant32(checksum, action.unknown.data_size)
    checksum.extend(action.unknown.data_chunk)

    writers.write_bytes_unchecked(w, action.unknown.data_chunk)
    bytes_left = action.unknown.data_size - len(action.unknown.data_chunk)

    while bytes_left != 0:
        action = await ctx.call(EosTxActionRequest(data_size=bytes_left),
                                EosTxActionAck)

        if action.unknown is None:
            raise ValueError("Bad response. Unknown struct expected.")

        checksum.extend(action.unknown.data_chunk)
        writers.write_bytes_unchecked(w, action.unknown.data_chunk)

        bytes_left -= len(action.unknown.data_chunk)
        if bytes_left < 0:
            raise ValueError("Bad response. Buffer overflow.")

    await layout.confirm_action_unknown(ctx, action.common,
                                        checksum.get_digest())
Exemplo n.º 2
0
async def ethereum_sign_tx(ctx, msg):
    from trezor.crypto.hashlib import sha3_256

    msg = sanitize(msg)
    check(msg)

    data_total = msg.data_length

    # detect ERC - 20 token
    token = None
    recipient = msg.to
    value = int.from_bytes(msg.value, 'big')
    if len(msg.to) == 20 and \
       len(msg.value) == 0 and \
       data_total == 68 and \
       len(msg.data_initial_chunk) == 68 and \
       msg.data_initial_chunk[:16] == b'\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00':
        token = tokens.token_by_chain_address(msg.chain_id, msg.to)
        recipient = msg.data_initial_chunk[16:36]
        value = int.from_bytes(msg.data_initial_chunk[36:68], 'big')

    await require_confirm_tx(ctx, recipient, value, msg.chain_id, token)
    if token is None and msg.data_length > 0:
        await require_confirm_data(ctx, msg.data_initial_chunk, data_total)

    await require_confirm_fee(ctx, value, int.from_bytes(msg.gas_price, 'big'),
                              int.from_bytes(msg.gas_limit, 'big'),
                              msg.chain_id, token)

    data = bytearray()
    data += msg.data_initial_chunk
    data_left = data_total - len(msg.data_initial_chunk)

    total_length = get_total_length(msg, data_total)

    sha = HashWriter(sha3_256)
    sha.extend(rlp.encode_length(total_length, True))  # total length

    for field in [msg.nonce, msg.gas_price, msg.gas_limit, msg.to, msg.value]:
        sha.extend(rlp.encode(field))

    if data_left == 0:
        sha.extend(rlp.encode(data))
    else:
        sha.extend(rlp.encode_length(data_total, False))
        sha.extend(rlp.encode(data, False))

    while data_left > 0:
        resp = await send_request_chunk(ctx, data_left)
        data_left -= len(resp.data_chunk)
        sha.extend(resp.data_chunk)

    # eip 155 replay protection
    if msg.chain_id:
        sha.extend(rlp.encode(msg.chain_id))
        sha.extend(rlp.encode(0))
        sha.extend(rlp.encode(0))

    digest = sha.get_digest(True)  # True -> use keccak mode
    return await send_signature(ctx, msg, digest)
Exemplo n.º 3
0
async def sign_tx(
    ctx: wire.Context, msg: EosSignTx, keychain: seed.Keychain
) -> EosSignedTx:
    if msg.chain_id is None:
        raise wire.DataError("No chain id")
    if msg.header is None:
        raise wire.DataError("No header")
    if msg.num_actions is None or msg.num_actions == 0:
        raise wire.DataError("No actions")

    await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)

    node = keychain.derive(msg.address_n)
    sha = HashWriter(sha256())
    await _init(ctx, sha, msg)
    await _actions(ctx, sha, msg.num_actions)
    writers.write_variant32(sha, 0)
    writers.write_bytes(sha, bytearray(32))

    digest = sha.get_digest()
    signature = secp256k1.sign(
        node.private_key(), digest, True, secp256k1.CANONICAL_SIG_EOS
    )

    return EosSignedTx(signature=base58_encode("SIG_", "K1", signature))
Exemplo n.º 4
0
def address_multisig_p2wsh_in_p2sh(pubkeys: list[bytes], m: int,
                                   coin: CoinInfo) -> str:
    if coin.address_type_p2sh is None:
        raise wire.ProcessError("Multisig not enabled on this coin")
    witness_script_h = HashWriter(sha256())
    write_output_script_multisig(witness_script_h, pubkeys, m)
    return address_p2wsh_in_p2sh(witness_script_h.get_digest(), coin)
Exemplo n.º 5
0
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
    pubkeys = multisig.pubkeys
    m = multisig.m
    n = len(pubkeys)

    if n < 1 or n > 15 or m < 1 or m > 15:
        raise MultisigError(FailureType.DataError,
                            "Invalid multisig parameters")

    for hd in pubkeys:
        d = hd.node
        if len(d.public_key) != 33 or len(d.chain_code) != 32:
            raise MultisigError(FailureType.DataError,
                                "Invalid multisig parameters")

    # casting to bytes(), sorting on bytearray() is not supported in MicroPython
    pubkeys = sorted(pubkeys, key=lambda hd: bytes(hd.node.public_key))

    h = HashWriter(sha256)
    write_uint32(h, m)
    write_uint32(h, n)
    for hd in pubkeys:
        d = hd.node
        write_uint32(h, d.depth)
        write_uint32(h, d.fingerprint)
        write_uint32(h, d.child_num)
        write_bytes(h, d.chain_code)
        write_bytes(h, d.public_key)

    return h.get_digest()
Exemplo n.º 6
0
def message_digest(message):
    h = HashWriter(sha3_256(keccak=True))
    signed_message_header = "\x19Ethereum Signed Message:\n"
    h.extend(signed_message_header)
    h.extend(str(len(message)))
    h.extend(message)
    return h.get_digest()
Exemplo n.º 7
0
def message_digest(message):
    h = HashWriter(sha256())
    signed_message_header = 'Beam Signed Message:\n'
    h.extend(signed_message_header)
    h.extend(str(len(message)))
    h.extend(message)
    return sha256(h.get_digest()).digest()
Exemplo n.º 8
0
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
    if multisig.nodes:
        pubnodes = multisig.nodes
    else:
        pubnodes = [hd.node for hd in multisig.pubkeys]
    m = multisig.m
    n = len(pubnodes)

    if n < 1 or n > 15 or m < 1 or m > 15:
        raise wire.DataError("Invalid multisig parameters")

    for d in pubnodes:
        if len(d.public_key) != 33 or len(d.chain_code) != 32:
            raise wire.DataError("Invalid multisig parameters")

    # casting to bytes(), sorting on bytearray() is not supported in MicroPython
    pubnodes = sorted(pubnodes, key=lambda n: bytes(n.public_key))

    h = HashWriter(sha256())
    write_uint32(h, m)
    write_uint32(h, n)
    for d in pubnodes:
        write_uint32(h, d.depth)
        write_uint32(h, d.fingerprint)
        write_uint32(h, d.child_num)
        write_bytes_fixed(h, d.chain_code, 32)
        write_bytes_fixed(h, d.public_key, 33)

    return h.get_digest()
Exemplo n.º 9
0
    def sig_digest(
        self,
        txi: TxInput | None,
        script_pubkey: bytes | None,
    ) -> bytes:
        """
        Returns `S.2: transparent_sig_digest` field for signature
        digest computation.

        see: https://zips.z.cash/zip-0244#s-2-transparent-sig-digest
        """

        if self.empty:
            assert txi is None
            assert script_pubkey is None
            return self.digest()

        h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash"))

        # only SIGHASH_ALL is supported in Trezor
        write_uint8(h, SigHashType.SIGHASH_ALL)  # S.2a
        write_hash(h, self.prevouts.get_digest())  # S.2b
        write_hash(h, self.amounts.get_digest())  # S.2c
        write_hash(h, self.scriptpubkeys.get_digest())  # S.2d
        write_hash(h, self.sequence.get_digest())  # S.2e
        write_hash(h, self.outputs.get_digest())  # S.2f
        write_hash(h, _txin_sig_digest(txi, script_pubkey))  # S.2g

        return h.get_digest()
Exemplo n.º 10
0
    async def verify_original_txs(self) -> None:
        for orig in self.orig_txs:
            # should come out the same as h_inputs_check, checked before continuing
            h_check = HashWriter(sha256())

            for i in range(orig.tx.inputs_count):
                txi = await helpers.request_tx_input(
                    self.tx_req, i, self.coin, orig.orig_hash
                )
                writers.write_tx_input_check(h_check, txi)
                script_pubkey = self.input_derive_script(txi)
                verifier = SignatureVerifier(
                    script_pubkey, txi.script_sig, txi.witness, self.coin
                )
                verifier.ensure_hash_type(
                    (SigHashType.SIGHASH_ALL_TAPROOT, self.get_sighash_type(txi))
                )
                tx_digest = await self.get_tx_digest(
                    i,
                    txi,
                    orig,
                    verifier.public_keys,
                    verifier.threshold,
                    script_pubkey,
                )
                verifier.verify(tx_digest)

            # check that the inputs were the same as those streamed for approval
            if h_check.get_digest() != orig.h_inputs_check:
                raise wire.ProcessError("Transaction has changed during signing")
Exemplo n.º 11
0
def get_tx_hash(w: HashWriter, double: bool = False, reverse: bool = False) -> bytes:
    d = w.get_digest()
    if double:
        d = sha256(d).digest()
    if reverse:
        d = bytes(reversed(d))
    return d
Exemplo n.º 12
0
async def sign_tx(ctx: wire.Context, msg: EthereumSignTx,
                  keychain: Keychain) -> EthereumTxRequest:
    check(msg)
    await paths.validate_path(ctx, keychain, msg.address_n)

    # Handle ERC20s
    token, address_bytes, recipient, value = await handle_erc20(ctx, msg)

    data_total = msg.data_length

    await require_confirm_tx(ctx, recipient, value, msg.chain_id, token)
    if token is None and msg.data_length > 0:
        await require_confirm_data(ctx, msg.data_initial_chunk, data_total)

    await require_confirm_fee(
        ctx,
        value,
        int.from_bytes(msg.gas_price, "big"),
        int.from_bytes(msg.gas_limit, "big"),
        msg.chain_id,
        token,
    )

    data = bytearray()
    data += msg.data_initial_chunk
    data_left = data_total - len(msg.data_initial_chunk)

    total_length = get_total_length(msg, data_total)

    sha = HashWriter(sha3_256(keccak=True))
    rlp.write_header(sha, total_length, rlp.LIST_HEADER_BYTE)

    if msg.tx_type is not None:
        rlp.write(sha, msg.tx_type)

    for field in (msg.nonce, msg.gas_price, msg.gas_limit, address_bytes,
                  msg.value):
        rlp.write(sha, field)

    if data_left == 0:
        rlp.write(sha, data)
    else:
        rlp.write_header(sha, data_total, rlp.STRING_HEADER_BYTE, data)
        sha.extend(data)

    while data_left > 0:
        resp = await send_request_chunk(ctx, data_left)
        data_left -= len(resp.data_chunk)
        sha.extend(resp.data_chunk)

    # eip 155 replay protection
    rlp.write(sha, msg.chain_id)
    rlp.write(sha, 0)
    rlp.write(sha, 0)

    digest = sha.get_digest()
    result = sign_digest(msg, keychain, digest)

    return result
Exemplo n.º 13
0
def message_digest(message):
    h = HashWriter(sha256)
    signed_message_header = "Lisk Signed Message:\n"
    write_varint(h, len(signed_message_header))
    h.extend(signed_message_header)
    write_varint(h, len(message))
    h.extend(message)
    return sha256(h.get_digest()).digest()
Exemplo n.º 14
0
class TxInfoBase:
    def __init__(self, signer: Signer) -> None:
        # Checksum of multisig inputs, used to validate change-output.
        self.multisig_fingerprint = MultisigFingerprintChecker()

        # Common prefix of input paths, used to validate change-output.
        self.wallet_path = WalletPathChecker()

        # h_tx_check is used to make sure that the inputs and outputs streamed in
        # different steps are the same every time, e.g. the ones streamed for approval
        # in Steps 1 and 2 and the ones streamed for signing legacy inputs in Step 4.
        self.h_tx_check = HashWriter(sha256())  # not a real tx hash

        # BIP-0143 transaction hashing.
        self.hash143 = signer.create_hash143()

        # The minimum nSequence of all inputs.
        self.min_sequence = _SEQUENCE_FINAL

    def add_input(self, txi: TxInput) -> None:
        self.hash143.add_input(
            txi)  # all inputs are included (non-segwit as well)
        writers.write_tx_input_check(self.h_tx_check, txi)
        self.min_sequence = min(self.min_sequence, txi.sequence)

        if not input_is_external(txi):
            self.wallet_path.add_input(txi)
            self.multisig_fingerprint.add_input(txi)

    def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
        self.hash143.add_output(txo, script_pubkey)
        writers.write_tx_output(self.h_tx_check, txo, script_pubkey)

    def check_input(self, txi: TxInput) -> None:
        self.wallet_path.check_input(txi)
        self.multisig_fingerprint.check_input(txi)

    def output_is_change(self, txo: TxOutput) -> bool:
        if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES:
            return False
        if txo.multisig and not self.multisig_fingerprint.output_matches(txo):
            return False
        return (self.wallet_path.output_matches(txo)
                and len(txo.address_n) >= BIP32_WALLET_DEPTH
                and txo.address_n[-2] <= _BIP32_CHANGE_CHAIN
                and txo.address_n[-1] <= _BIP32_MAX_LAST_ELEMENT
                and txo.amount > 0)

    def lock_time_disabled(self) -> bool:
        return self.min_sequence == _SEQUENCE_FINAL

    def rbf_disabled(self) -> bool:
        return self.min_sequence > _MAX_BIP125_RBF_SEQUENCE

    def get_tx_check_digest(self) -> bytes:
        return self.h_tx_check.get_digest()
Exemplo n.º 15
0
def message_digest(coin, message):
    h = HashWriter(sha256)
    write_varint(h, len(coin.signed_message_header))
    h.extend(coin.signed_message_header)
    write_varint(h, len(message))
    h.extend(message)
    ret = h.get_digest()
    if coin.sign_hash_double:
        ret = sha256(ret).digest()
    return ret
Exemplo n.º 16
0
def generate_proof(
    node: bip32.HDNode,
    script_type: InputScriptType,
    multisig: MultisigRedeemScriptType | None,
    coin: CoinInfo,
    user_confirmed: bool,
    ownership_ids: list[bytes],
    script_pubkey: bytes,
    commitment_data: bytes,
) -> tuple[bytes, bytes]:
    flags = 0
    if user_confirmed:
        flags |= _FLAG_USER_CONFIRMED

    proof = utils.empty_bytearray(4 + 1 + 1 +
                                  len(ownership_ids) * _OWNERSHIP_ID_LEN)

    write_bytes_fixed(proof, _VERSION_MAGIC, 4)
    write_uint8(proof, flags)
    write_bitcoin_varint(proof, len(ownership_ids))
    for ownership_id in ownership_ids:
        write_bytes_fixed(proof, ownership_id, _OWNERSHIP_ID_LEN)

    sighash = HashWriter(sha256(proof))
    write_bytes_prefixed(sighash, script_pubkey)
    write_bytes_prefixed(sighash, commitment_data)
    if script_type in (
            InputScriptType.SPENDADDRESS,
            InputScriptType.SPENDMULTISIG,
            InputScriptType.SPENDWITNESS,
            InputScriptType.SPENDP2SHWITNESS,
    ):
        signature = common.ecdsa_sign(node, sighash.get_digest())
    elif script_type == InputScriptType.SPENDTAPROOT:
        signature = common.bip340_sign(node, sighash.get_digest())
    else:
        raise wire.DataError("Unsupported script type.")
    public_key = node.public_key()
    write_bip322_signature_proof(proof, script_type, multisig, coin,
                                 public_key, signature)

    return proof, signature
Exemplo n.º 17
0
def message_digest(coin: CoinType, message: bytes) -> bytes:
    if coin.decred:
        h = HashWriter(blake256())
    else:
        h = HashWriter(sha256())
    write_varint(h, len(coin.signed_message_header))
    h.extend(coin.signed_message_header)
    write_varint(h, len(message))
    h.extend(message)
    ret = h.get_digest()
    if coin.sign_hash_double:
        ret = sha256(ret).digest()
    return ret
Exemplo n.º 18
0
def message_digest(message):
    from apps.wallet.sign_tx.signing import write_varint
    from trezor.crypto.hashlib import sha3_256
    from trezor.utils import HashWriter

    h = HashWriter(sha3_256)
    signed_message_header = 'Ethereum Signed Message:\n'
    write_varint(h, len(signed_message_header))
    h.extend(signed_message_header)
    write_varint(h, len(message))
    h.extend(message)

    return h.get_digest(True)
Exemplo n.º 19
0
    def test_p2wsh_address(self):
        coin = coins.by_name('Testnet')

        # pubkey OP_CHECKSIG
        script = unhexlify('210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac')
        h = HashWriter(sha256())
        write_bytes_unchecked(h, script)

        address = address_p2wsh(
            h.get_digest(),
            coin.bech32_prefix
        )
        self.assertEqual(address, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7')
Exemplo n.º 20
0
    async def step3_verify_inputs(self) -> None:
        # should come out the same as h_inputs_check, checked before continuing
        h_check = HashWriter(sha256())

        if self.taproot_only:
            # All internal inputs are Taproot. We only need to verify external inputs. We can trust
            # the amounts and scriptPubKeys, because if an invalid value is provided then all
            # issued signatures will be invalid.
            expected_digest = self.h_external_inputs
            for i in self.external:
                progress.advance()
                txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
                writers.write_tx_input_check(h_check, txi)
                if not input_is_external_unverified(txi):
                    assert txi.script_pubkey is not None  # checked in sanitize_tx_input
                    await self.verify_external_input(i, txi, txi.script_pubkey)

            progress.advance(self.tx_info.tx.inputs_count - len(self.external))
        else:
            # There are internal non-Taproot inputs. We need to verify all inputs, because we can't
            # trust any amounts or scriptPubKeys. If we did, then an attacker who provides invalid
            # information about amounts, scriptPubKeys and/or script types may still obtain valid
            # signatures for legacy and SegWit v0 inputs. These valid signatures could be exploited
            # in subsequent signing operations to falsely claim externality of the already signed
            # inputs or to falsely claim that a transaction is a replacement of an already approved
            # transaction or to construct a valid transaction by combining signatures obtained in
            # multiple rounds of the attack.
            expected_digest = self.tx_info.h_inputs_check
            for i in range(self.tx_info.tx.inputs_count):
                progress.advance()
                txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
                writers.write_tx_input_check(h_check, txi)

                prev_amount, script_pubkey = await self.get_prevtx_output(
                    txi.prev_hash, txi.prev_index
                )
                if prev_amount != txi.amount:
                    raise wire.DataError("Invalid amount specified")

                if script_pubkey != self.input_derive_script(txi):
                    raise wire.DataError("Input does not match scriptPubKey")

                if i in self.external and not input_is_external_unverified(txi):
                    await self.verify_external_input(i, txi, script_pubkey)

        # check that the inputs were the same as those streamed for approval
        if h_check.get_digest() != expected_digest:
            raise wire.ProcessError("Transaction has changed during signing")

        # verify the signature of one SIGHASH_ALL input in each original transaction
        await self.verify_original_txs()
Exemplo n.º 21
0
    def txid_digest(self) -> bytes:
        """
        Returns the transaction identifier.

        see: https://zips.z.cash/zip-0244#id4
        """
        h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person))

        write_hash(h, self.header.digest())  # T.1
        write_hash(h, self.transparent.digest())  # T.2
        write_hash(h, self.sapling.digest())  # T.3
        write_hash(h, self.orchard.digest())  # T.4

        return h.get_digest()
Exemplo n.º 22
0
    def digest(self) -> bytes:
        """
        Returns `T.2: transparent_digest` field for txid computation.

        see: https://zips.z.cash/zip-0244#t-2-transparent-digest
        """
        h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash"))

        if not self.empty:
            write_hash(h, self.prevouts.get_digest())  # T.2a
            write_hash(h, self.sequence.get_digest())  # T.2b
            write_hash(h, self.outputs.get_digest())  # T.2c

        return h.get_digest()
Exemplo n.º 23
0
    def __init__(self, tx: SignTx | PrevTx):
        h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdHeadersHash"))

        assert tx.version_group_id is not None
        assert tx.branch_id is not None  # checked in sanitize_*
        assert tx.expiry is not None

        write_uint32(h, tx.version | (1 << 31))  # T.1a
        write_uint32(h, tx.version_group_id)  # T.1b
        write_uint32(h, tx.branch_id)  # T.1c
        write_uint32(h, tx.lock_time)  # T.1d
        write_uint32(h, tx.expiry)  # T.1e

        self._digest = h.get_digest()
Exemplo n.º 24
0
async def sign_tx(ctx, msg, keychain):
    await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n,
                              CURVE)

    address_bytes = recipient = address.bytes_from_address(msg.to)
    value = int.from_bytes(msg.value, "big")
    recipient = msg.data_initial_chunk[16:36]
    value = int.from_bytes(msg.data_initial_chunk[36:68], "big")

    await require_confirm_tx(ctx, recipient, value, msg.chain_id, token,
                             msg.tx_type)

    data = bytearray()
    data += msg.data_initial_chunk
    data_left = data_total - len(msg.data_initial_chunk)

    total_length = get_total_length(msg, data_total)

    sha = HashWriter(sha3_256(keccak=True))
    sha.extend(rlp.encode_length(total_length, True))  # total length

    if msg.tx_type is not None:
        sha.extend(rlp.encode(msg.tx_type))

    for field in (msg.nonce, msg.gas_price, msg.gas_limit, address_bytes,
                  msg.value):
        sha.extend(rlp.encode(field))

    if data_left == 0:
        sha.extend(rlp.encode(data))
    else:
        sha.extend(rlp.encode_length(data_total, False))
        sha.extend(rlp.encode(data, False))

    while data_left > 0:
        resp = await send_request_chunk(ctx, data_left)
        data_left -= len(resp.data_chunk)
        sha.extend(resp.data_chunk)

    # eip 155 replay protection
    if msg.chain_id:
        sha.extend(rlp.encode(msg.chain_id))
        sha.extend(rlp.encode(0))
        sha.extend(rlp.encode(0))

    digest = sha.get_digest()
    result = sign_digest(msg, keychain, digest)

    return result
Exemplo n.º 25
0
    def signature_digest(
        self, txi: TxInput | None, script_pubkey: bytes | None
    ) -> bytes:
        """
        Returns the transaction signature digest.

        see: https://zips.z.cash/zip-0244#id13
        """
        h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person))

        write_hash(h, self.header.digest())  # S.1
        write_hash(h, self.transparent.sig_digest(txi, script_pubkey))  # S.2
        write_hash(h, self.sapling.digest())  # S.3
        write_hash(h, self.orchard.digest())  # S.4

        return h.get_digest()
Exemplo n.º 26
0
def verify_nonownership(
    proof: bytes,
    script_pubkey: bytes,
    commitment_data: bytes | None,
    keychain: Keychain,
    coin: CoinInfo,
) -> bool:
    try:
        r = utils.BufferReader(proof)
        if r.read_memoryview(4) != _VERSION_MAGIC:
            raise wire.DataError("Unknown format of proof of ownership")

        flags = r.get()
        if flags & 0b1111_1110:
            raise wire.DataError("Unknown flags in proof of ownership")

        # Determine whether our ownership ID appears in the proof.
        id_count = read_bitcoin_varint(r)
        ownership_id = get_identifier(script_pubkey, keychain)
        not_owned = True
        for _ in range(id_count):
            if utils.consteq(ownership_id,
                             r.read_memoryview(_OWNERSHIP_ID_LEN)):
                not_owned = False

        # Verify the BIP-322 SignatureProof.

        proof_body = memoryview(proof)[:r.offset]
        if commitment_data is None:
            commitment_data = bytes()

        sighash = HashWriter(sha256(proof_body))
        write_bytes_prefixed(sighash, script_pubkey)
        write_bytes_prefixed(sighash, commitment_data)
        script_sig, witness = read_bip322_signature_proof(r)

        # We don't call verifier.ensure_hash_type() to avoid possible compatibility
        # issues between implementations, because the hash type doesn't influence
        # the digest and the value to use is not defined in BIP-322.
        verifier = SignatureVerifier(script_pubkey, script_sig, witness, coin)
        verifier.verify(sighash.get_digest())
    except (ValueError, EOFError):
        raise wire.DataError("Invalid proof of ownership")

    return not_owned
Exemplo n.º 27
0
async def sign_tx(ctx: wire.Context, msg: EosSignTx,
                  keychain: Keychain) -> EosSignedTx:
    if not msg.num_actions:
        raise wire.DataError("No actions")

    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)
    sha = HashWriter(sha256())
    await _init(ctx, sha, msg)
    await _actions(ctx, sha, msg.num_actions)
    writers.write_uvarint(sha, 0)
    writers.write_bytes_fixed(sha, bytearray(32), 32)

    digest = sha.get_digest()
    signature = secp256k1.sign(node.private_key(), digest, True,
                               secp256k1.CANONICAL_SIG_EOS)

    return EosSignedTx(signature=base58_encode("SIG_", "K1", signature))
Exemplo n.º 28
0
class DecredPrefixHasher:
    """
    While Decred does not have the exact same implementation as bip143/zip143,
    the semantics for using the prefix hash of transactions are close enough
    that a pseudo-bip143 class can be used to store the prefix hash during the
    check_fee stage of transaction signature to then reuse it at the sign_tx
    stage without having to request the inputs again.
    """
    def __init__(self, tx: SignTx):
        self.h_prefix = HashWriter(blake256())
        self.last_output_bytes = None
        write_uint32(self.h_prefix, tx.version | DECRED_SERIALIZE_NO_WITNESS)
        write_varint(self.h_prefix, tx.inputs_count)

    def add_prevouts(self, txi: TxInputType):
        write_tx_input_decred(self.h_prefix, txi)

    def add_sequence(self, txi: TxInputType):
        pass

    def add_output_count(self, tx: SignTx):
        write_varint(self.h_prefix, tx.outputs_count)

    def add_output(self, txo_bin: TxOutputBinType):
        write_tx_output(self.h_prefix, txo_bin)

    def set_last_output_bytes(self, w_txo_bin: bytearray):
        """
        This is required because the last serialized output obtained in
        `check_fee` will only be sent to the client in `sign_tx`
        """
        self.last_output_bytes = w_txo_bin

    def get_last_output_bytes(self):
        return self.last_output_bytes

    def add_locktime_expiry(self, tx: SignTx):
        write_uint32(self.h_prefix, tx.lock_time)
        write_uint32(self.h_prefix, tx.expiry)

    def prefix_hash(self) -> bytes:
        return self.h_prefix.get_digest()
Exemplo n.º 29
0
async def sign_tx(ctx, msg):
    pubkey, seckey = await _get_keys(ctx, msg)
    transaction = _update_raw_tx(msg.transaction, pubkey)

    try:
        await _require_confirm_by_type(ctx, transaction)
    except AttributeError:
        raise wire.DataError("The transaction has invalid asset data field")

    await layout.require_confirm_fee(ctx, transaction.amount, transaction.fee)

    txbytes = _get_transaction_bytes(transaction)
    txhash = HashWriter(sha256())
    for field in txbytes:
        txhash.extend(field)
    digest = txhash.get_digest()

    signature = ed25519.sign(seckey, digest)

    return LiskSignedTx(signature=signature)
Exemplo n.º 30
0
def _txin_sig_digest(
    txi: TxInput | None,
    script_pubkey: bytes | None,
) -> bytes:
    """
    Returns `S.2g: txin_sig_digest` field for signature digest computation.

    see: https://zips.z.cash/zip-0244#s-2g-txin-sig-digest
    """

    h = HashWriter(blake2b(outlen=32, personal=b"Zcash___TxInHash"))

    if txi is not None:
        assert script_pubkey is not None

        write_prevout(h, txi)  # 2.Sg.i
        write_uint64(h, txi.amount)  # 2.Sg.ii
        write_bytes_prefixed(h, script_pubkey)  # 2.Sg.iii
        write_uint32(h, txi.sequence)  # 2.Sg.iv

    return h.get_digest()