chore(tests): long values in payment requests
What changed, and why it matters
This commit only adds new automated tests. It checks that Trezor devices correctly reject payment-request amounts encoded with the wrong number of bytes (for Bitcoin) or values that are too large (for Ethereum). There is no change to the actual firmware or production code, and the commit message explicitly marks itself as a test-only chore with no changelog.
No action required. This is a test-only commit. Reviewers may optionally verify that the corresponding firmware validation already exists and that these tests pass in CI.
Security signals we found
Tests assert that malformed payment-request amount encodings are rejected by the device
Existing validation messages ('amount must be exactly 8 bytes', 'amount must be exactly 32 bytes') imply prior length checks in firmware
Evidence from the diff
The diff adds two test cases. In tests/device_tests/bitcoin/test_signtx_payreq.py it adds test_payment_req_amount_encoding_bytes, which re-encodes a BTC payment-request amount on 16 bytes and asserts the device returns ‘amount must be exactly 8 bytes’. In tests/device_tests/ethereum/test_signtx.py it updates an existing long-value test vector to use a 9-byte value and adds example_input_data_too_long_value with a >32-byte value, asserting the device rejects it with ‘amount must be exactly 32 bytes’. No firmware source is modified.
Changed components
tests/device_tests/bitcoin/test_signtx_payreq.pytests/device_tests/ethereum/test_signtx.pyInspect captured patch +70 / −3
diff --git a/tests/device_tests/bitcoin/test_signtx_payreq.py b/tests/device_tests/bitcoin/test_signtx_payreq.py
index d699e0fc..7578d3df 100644
--- a/tests/device_tests/bitcoin/test_signtx_payreq.py
+++ b/tests/device_tests/bitcoin/test_signtx_payreq.py
@@ -308,6 +308,35 @@ def test_payment_req_wrong_amount(session: Session):
)
+def test_payment_req_amount_encoding_bytes(session: Session):
+ # Test payment request with amount encoded on too many bytes
+ outputs[0].payment_req_index = 0
+ outputs[1].payment_req_index = 0
+ outputs[2].payment_req_index = None
+ payment_req = make_payment_request(
+ session,
+ recipient_name="trezor.io",
+ slip44=1,
+ outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
+ nonce=misc.get_nonce(session),
+ )
+
+ # BTC amounts are supposed to be 8 bytes, here we re-encode the amount on more bytes
+ payment_req.amount = (int.from_bytes(payment_req.amount, "little")).to_bytes(
+ 16, "little"
+ )
+
+ with pytest.raises(TrezorFailure, match="amount must be exactly 8 bytes"):
+ btc.sign_tx(
+ session,
+ "Testnet",
+ inputs,
+ outputs,
+ prev_txes=PREV_TXES,
+ payment_reqs=[payment_req],
+ )
+
+
def test_payment_req_wrong_mac_refund(session: Session):
# Test wrong MAC in payment request memo.
memo = RefundMemo(parse_path("m/44h/1h/0h/1/0"))
diff --git a/tests/device_tests/ethereum/test_signtx.py b/tests/device_tests/ethereum/test_signtx.py
index 2cf2052c..e1e60876 100644
--- a/tests/device_tests/ethereum/test_signtx.py
+++ b/tests/device_tests/ethereum/test_signtx.py
@@ -137,15 +137,34 @@ example_input_data_long_value = {
"nonce": "0x0",
"gas_price": "0x4a817c800",
"gas_limit": "0x125208",
- "value": "0xab54a98ceb1f0ad2",
+ "value": "0x59b09a229d59205d2", # 103.405359019777459666 ETH - a value that will not fit in 8 bytes, but ETH allows 32 bytes
"to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
"tx_type": None,
"data": "",
},
"result": {
"sig_v": 37,
- "sig_r": "a396a13c67594d0df54a2cea8579f69eb185ab0b69bfa30a4c15fd9ac44eb88d",
- "sig_s": "0eb91df671c175ecfe60e4ab5a02e9627b94a19dd252f75344ea679934581f39",
+ "sig_r": "e398a281bab316c5d0192b8e1f6d7a9f1698f6ba2ada4efd8337d4dd2ac7fca4",
+ "sig_s": "5e5caa4a8b51bd5d9b4d7ad4c2c5a62875fbbbf9dc71eb1fb2f76807e5aa23db",
+ },
+}
+
+example_input_data_too_long_value = {
+ "parameters": {
+ "chain_id": 1,
+ "path": "m/44'/60'/0'/0/0",
+ "nonce": "0x0",
+ "gas_price": "0x4a817c800",
+ "gas_limit": "0x125208",
+ "value": "0x10000000000000000000000000000000000000000000000000000000000000000", # > 32 bytes
+ "to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98",
+ "tx_type": None,
+ "data": "",
+ },
+ "result": {
+ "sig_v": 37,
+ "sig_r": "e398a281bab316c5d0192b8e1f6d7a9f1698f6ba2ada4efd8337d4dd2ac7fca4",
+ "sig_s": "5e5caa4a8b51bd5d9b4d7ad4c2c5a62875fbbbf9dc71eb1fb2f76807e5aa23db",
},
}
@@ -673,3 +692,22 @@ def test_signtx_payment_req_long_value(
params,
example_input_data_long_value["result"],
)
+
+ params = dict(example_input_data_too_long_value["parameters"])
+ params["payment_req"] = make_payment_request(
+ session,
+ recipient_name="trezor.io",
+ slip44=60,
+ outputs=[(int(params["value"], 16), params["to_address"])],
+ memos=memos,
+ nonce=nonce,
+ amount_size_bytes=64,
+ )
+
+ with pytest.raises(exceptions.TrezorFailure) as e:
+ _do_test_signtx(
+ session,
+ params,
+ example_input_data_long_value["result"],
+ )
+ assert str(e.value.message) == "amount must be exactly 32 bytes"
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.