Skip to content

Commit f9e2414

Browse files
Merge pull request #60 from BitHighlander/feat/certified-solana-lut-alpha
test(solana): bind certified ClearSign envelopes
2 parents 8e59e4c + 81fb1c4 commit f9e2414

5 files changed

Lines changed: 98 additions & 13 deletions

File tree

keepkeylib/messages_solana_pb2.py

Lines changed: 19 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/test_dylib_confirm_flow.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ def test_features_round_trip(self):
7575
self.client.init_device()
7676
f = self.client.features
7777
self.assertGreaterEqual(f.major_version, 7)
78+
revision = f.revision.decode("ascii")
79+
self.assertRegex(revision, r"^[0-9a-f]{40}$")
80+
expected_revision = os.environ.get("GITHUB_SHA")
81+
if expected_revision:
82+
self.assertEqual(revision, expected_revision)
7883

7984
@unittest.skip(
8085
"Pending firmware fix — confirm_helper busy-loops on a ButtonAck "

tests/test_message_signing_protocol_bindings.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ def test_solana_recipient_owner_hint_is_additive_field_12(self):
3232
decoded = solana_proto.SolanaSignTx.FromString(encoded)
3333
self.assertEqual(list(decoded.token_recipient_owner), [owner])
3434

35+
def test_solana_clearsign_certificate_is_additive_field_13(self):
36+
field = solana_proto.SolanaSignTx.DESCRIPTOR.fields_by_name[
37+
'clearsign_certificate'
38+
]
39+
self.assertEqual(field.number, 13)
40+
if hasattr(field, 'label'):
41+
self.assertEqual(field.label, field.LABEL_OPTIONAL)
42+
else:
43+
self.assertFalse(field.is_repeated)
44+
self.assertEqual(field.type, field.TYPE_BYTES)
45+
46+
certificate = bytes(range(139))
47+
encoded = solana_proto.SolanaSignTx(
48+
address_n=[0x8000002c, 0x800001f5, 0x80000000, 0x80000000],
49+
raw_tx=b'\x80relay',
50+
schema_payload=b'\x01schema',
51+
schema_signature=bytes(range(64)),
52+
schema_signer_key_id=0x80,
53+
clearsign_certificate=certificate,
54+
).SerializeToString()
55+
decoded = solana_proto.SolanaSignTx.FromString(encoded)
56+
self.assertEqual(decoded.clearsign_certificate, certificate)
57+
self.assertEqual(decoded.schema_signer_key_id, 0x80)
58+
3559
def test_solana_offchain_messages_are_mapped(self):
3660
self.assertEqual(proto.MessageType_SolanaSignOffchainMessage, 756)
3761
self.assertEqual(proto.MessageType_SolanaOffchainMessageSignature, 757)

tests/test_msg_solana_signtx.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,55 @@ def test_solana_sign_versioned_v0_static_verified(self):
919919
self.assertEqual(len(resp.signature), 64)
920920
self.assertFalse(all(b == 0 for b in resp.signature))
921921

922+
def test_relay_certified_v0_no_lookup_proof_reaches_signer_check(self):
923+
"""The exact public Relay proof used by Vault must enter ClearSign.
924+
925+
The captured transaction belongs to the operator, not this test's
926+
mnemonic, so the final signer check must reject it. That later,
927+
specific rejection is intentional: it proves the certificate and
928+
schema survived protobuf decoding and passed the production FSM proof
929+
gate without requiring an operator secret or approving a transaction.
930+
"""
931+
self.requires_firmware("7.16.0")
932+
self.requires_fullFeature()
933+
self.setup_mnemonic_allallall()
934+
935+
raw_tx = binascii.unhexlify(
936+
"8001000305ec3979a4dc6b401bd045171a189f26856fab9eab75560214f972b2"
937+
"edc164300f66963b37e581dc14a0f573eeede8e54a257d83d082c54ab208cbff"
938+
"d1dc2a70ca792689378ecd51d80406eb0caa3b62795beb10b6c5dc96bc2e0df0"
939+
"3cbfee1abfbe3e6d285d2ee963351b6deeb0a1e96c881435ccd450b2645f24cc"
940+
"27960bee47000000000000000000000000000000000000000000000000000000"
941+
"0000000000d96db9f622f840ffda97430208ddbc7950d2c1ea45ecc9c2933151"
942+
"c02963f3860102050300000104300d9e0ddf5fd51c06f075633b000000000370"
943+
"4dea2a5eb9cf98e2f625a96080df1f0c5c24ccec3a6d8827b3ab25c0b11800")
944+
schema_payload = binascii.unhexlify(
945+
"4b4b534f4c53433101792689378ecd51d80406eb0caa3b62795beb10b6c5dc96"
946+
"bc2e0df03cbfee1abf080d9e0ddf5fd51c060c52656c6179204272696467650d"
947+
"6465706f7369744e6174697665020506416d6f756e7404054f72646572010305"
948+
"5661756c74")
949+
schema_signature = binascii.unhexlify(
950+
"801b309d284ae89287a21a6acbd5c63f999515f3ff6bf71d72a256485321b892"
951+
"7b7ebc3a26ace3df5551b85a68df8e9f1ef8eac220d85f4bfaa33d43b5349061")
952+
certificate = binascii.unhexlify(
953+
"0101000001f56c68c8804b6565704b6579205661756c74000000000000000000"
954+
"000000000000000000000342f5f9704494b3f9bd72295eecaf29d783d23ea02"
955+
"b2dc9f48abcd2e46d4850cfa2753fac6068a45747a32a4a39f249af72b55370f"
956+
"3491913b7fb9a80207d619b3b4fca6750fc1fdc790da5562b42a351e12cde3c"
957+
"0f084056a24ca8d1bf2c36b5")
958+
959+
self.client.apply_policy('AdvancedMode', False)
960+
with pytest.raises(CallException) as exc:
961+
self.client.call(messages.SolanaSignTx(
962+
address_n=parse_path("m/44'/501'/0'/0'"),
963+
raw_tx=raw_tx,
964+
schema_payload=schema_payload,
965+
schema_signature=schema_signature,
966+
schema_signer_key_id=128,
967+
clearsign_certificate=certificate,
968+
))
969+
self.assertIn("Derived key is not a signer for this tx", str(exc.value))
970+
922971
def test_solana_sign_x402_zero_lut_usdc_payment(self):
923972
"""Official x402 SVM shape clear-signs without blind signing.
924973

0 commit comments

Comments
 (0)