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)
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
async def sign_tx(ctx, msg, keychain): msg = sanitize(msg) check(msg) await paths.validate_path(ctx, keychain, 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") if token is tokens.UNKNOWN_TOKEN: await require_confirm_unknown_token(ctx, address_bytes) 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
async def sign_tx(ctx, msg, keychain): msg = sanitize(msg) #TODO refine `sanitize` to support more fields check(msg) #TODO refine check to support ~ await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE) node = keychain.derive(msg.address_n) seckey = node.private_key() public_key = secp256k1.publickey(seckey, False) # uncompressed sender_address = sha3_256(public_key[1:], keccak=True).digest()[12:] recipient = address.bytes_from_address(msg.to) # TODO- check sender and real sender addr value = int.from_bytes(msg.value, "big") await require_confirm_tx(ctx, recipient, value, msg.chain_id, None, msg.tx_type) # TODO if fee delegation tx? -> require_confirm_fee_delegation await require_confirm_fee( ctx, value, int.from_bytes(msg.gas_price, "big"), int.from_bytes(msg.gas_limit, "big"), msg.chain_id, msg.fee_ratio, None, msg.tx_type, ) data_total = msg.data_length data = bytearray() data += msg.data_initial_chunk data_left = data_total - len(msg.data_initial_chunk) total_length = get_total_length(msg, data_total) print("total length: ", total_length) sha = HashWriter(sha3_256(keccak=True)) if msg.tx_type is None: sha.extend(rlp.encode_length(total_length, True)) # total length for field in (msg.nonce, msg.gas_price, msg.gas_limit, recipient, 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)) if msg.chain_id: sha.extend(rlp.encode(msg.chain_id)) sha.extend(rlp.encode(0)) sha.extend(rlp.encode(0)) else: basic_type = to_basic_type(msg.tx_type) attributes = [msg.tx_type, msg.nonce, msg.gas_price, msg.gas_limit] # TxTypeValueTransfer(0x08) if basic_type == 0x08: attributes += [recipient, msg.value, sender_address] if to_fee_type(msg.tx_type) == TX_TYPE_PARTIAL_FEE_DELEGATION: attributes.append(msg.fee_ratio) # TxTypeValueTransferMemo(0x10), TxTypeSmartContractExecution(0x30) elif basic_type == 0x10 or basic_type == 0x30: attributes += [recipient, msg.value, sender_address, data] if to_fee_type(msg.tx_type) == TX_TYPE_PARTIAL_FEE_DELEGATION: attributes.append(msg.fee_ratio) # TxTypeSmartContractDeploy(0x28) elif basic_type == 0x28: human_readable = 0x00 if msg.human_readable: human_readable = 0x01 attributes += [ recipient, msg.value, sender_address, data, human_readable ] if to_fee_type(msg.tx_type) == TX_TYPE_PARTIAL_FEE_DELEGATION: attributes.append(msg.fee_ratio) attributes.append(msg.code_format) # TxTypeCancel(0x38) elif basic_type == 0x38: attributes.append(sender_address) if to_fee_type(msg.tx_type) == TX_TYPE_PARTIAL_FEE_DELEGATION: attributes.append(msg.fee_ratio) # not supported tx type else: raise wire.DataError("Not supported transaction type") encoded_out = rlp.encode(attributes) sha.extend(rlp.encode([encoded_out, msg.chain_id, 0, 0], True)) digest = sha.get_digest() result = sign_digest(msg, keychain, digest) return result
def test_rlp_encode(self): for i, o in self.vectors: o = unhexlify(o) o2 = rlp.encode(i) self.assertEqual(o, o2)