Beispiel #1
0
def get_total_length(msg: EthereumSignTx, data_total: int) -> int:
    length = 0
    if msg.tx_type is not None:
        length += rlp.field_length(1, [msg.tx_type])

    length += rlp.field_length(len(msg.nonce), msg.nonce[:1])
    length += rlp.field_length(len(msg.gas_price), msg.gas_price)
    length += rlp.field_length(len(msg.gas_limit), msg.gas_limit)
    to = address.bytes_from_address(msg.to)
    length += rlp.field_length(len(to), to)
    length += rlp.field_length(len(msg.value), msg.value)

    if msg.chain_id:  # forks replay protection
        if msg.chain_id < 0x100:
            l = 1
        elif msg.chain_id < 0x10000:
            l = 2
        elif msg.chain_id < 0x1000000:
            l = 3
        else:
            l = 4
        length += rlp.field_length(l, [msg.chain_id])
        length += rlp.field_length(0, 0)
        length += rlp.field_length(0, 0)

    length += rlp.field_length(data_total, msg.data_initial_chunk)
    return length
Beispiel #2
0
async def verify_message(ctx, msg):
    digest = message_digest(msg.message)
    if len(msg.signature) != 65:
        raise wire.DataError("Invalid signature")
    sig = bytearray([msg.signature[64]]) + msg.signature[:64]

    try:
        pubkey = secp256k1.verify_recover(sig, digest)
    except ValueError:
        raise wire.DataError("Invalid signature")

    if not pubkey:
        raise wire.DataError("Invalid signature")

    pkh = sha3_256(pubkey[1:], keccak=True).digest()[-20:]

    address_bytes = bytes_from_address(msg.address)
    if address_bytes != pkh:
        raise wire.DataError("Invalid signature")

    address = address_from_bytes(address_bytes)

    await require_confirm_verify_message(ctx, address, msg.message)

    return Success(message="Message verified")
Beispiel #3
0
async def sign_tx(ctx, msg, keychain):
    msg = sanitize(msg)
    check(msg)
    await paths.validate_path(ctx, validate_full_path, path=msg.address_n)

    data_total = msg.data_length

    # detect ERC - 20 token
    token = None
    address_bytes = recipient = address.bytes_from_address(msg.to)
    value = int.from_bytes(msg.value, "big")
    if (len(msg.to) in (40, 42) 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, address_bytes)
        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)
    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,
        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