You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds protocol definitions for firmware 7.15: capability reporting, Taproot and dice modes, Ethereum runtime signers, streamed EIP-712, ERC-7730 definitions, Hive messages, NEAR schemas, Solana attestations, certified contacts, and Zcash wire v2 with breaking changes to batched transparent signatures. NEAR remains schema-only; firmware 7.15 has no handler.
EthereumClearSignDefinitionRequest.chain_id uses strings in generated JavaScript bindings to preserve the full uint64 range. Regressions check exact serialization and decoding through the maximum uint64 value. Documentation now specifies firmware 7.15's executable ERC-7730 subset, formatter roles and limits, and explains that legacy Zcash address tags are ignored: hosts must compare the returned address with the intended address.
Validation: Protocol CI passed at 6fd3e2700a175f80ad678432d9ca939d44a3f695, including package/binding validation, descriptor compilation and the Zcash wire-contract check.
Currently pinned by Python #197 at 45e2651a2 and the int12 firmware fork candidates. Updates for upstream firmware #483 and #477–#482 are staged locally and remain unpushed. Human review remains required.
New messages for displaying a Zcash unified address on the device screen
with FVK verification. The host provides the UA string and FVK components;
the device independently derives FVK from seed and verifies the match
before displaying the address with a QR code.
- ZcashDisplayAddress (wire_in 1308): address + ak/nk/rivk for verification
- ZcashAddress (wire_out 1309): confirmed address after user approval
- nanopb options: address max_size:128, key fields max_size:32
The device only verifies the Orchard FVK — it cannot verify
transparent or Sapling receivers that may also be bundled in
a Unified Address. Updated proto comments to explicitly state
the guarantee: "This UA contains an Orchard receiver from this
account" rather than implying full address ownership.
Also clarified that account or address_n is required (no silent
fallback to account 0).
…TIP-712)
Adds proto definitions for TRON message-signing parity:
- TronSignMessage / TronMessageSignature (1404/1405) — TIP-191 personal_sign
- TronVerifyMessage (1406) — host-asserted signature verification
- TronSignTypedHash / TronTypedDataSignature (1407/1408) — TIP-712 hash mode
Mirrors the Ethereum personal_sign + EIP-712 hash-mode shape. Firmware
implementation will reuse the secp256k1 + keccak256 primitives already
present for Ethereum, swapping the message prefix to '\x19TRON Signed Message:\n'
for TIP-191 and using '\x19\x01' for TIP-712.
Reserves IDs 1404-1408 contiguous to existing TRON range (1400-1403).
Adds TonSignMessage / TonMessageSignature (1504/1505) — basic Ed25519
arbitrary-bytes signing, mirroring SolanaSignMessage's shape.
This primitive lacks domain separation by design (raw Ed25519 over message
bytes). Firmware should gate it behind the AdvancedMode policy — same
fence used for SolanaSignMessage in fsm_msg_solana.h — until a TON
Connect ton_proof envelope is added as a separate proto.
Reserves IDs 1504-1505 contiguous to existing TON range (1500-1503).
Adds SolanaSignOffchainMessage / SolanaOffchainMessageSignature (756/757)
implementing the Solana off-chain message spec:
'\xff' || 'solana offchain' || version || format || length || message
The '\xff' lead byte is invalid as a Solana transaction prefix, providing
the domain separation that plain SolanaSignMessage (754/755) lacks. With
this primitive, firmware can drop the AdvancedMode policy gate currently
required for SolanaSignMessage (fsm_msg_solana.h:461-472) for ASCII/UTF8
off-chain messages, since the envelope makes transaction-shaped attacks
impossible.
message_format values per spec:
0 = Restricted ASCII (max 1212 bytes) — display-renderable
1 = UTF-8 limited (max 1212 bytes) — display-renderable with care
2 = UTF-8 extended (max 65515) — blind-sign only
Reserves IDs 756-757 contiguous to existing Solana range (750-755).
Bumped message max_size to 1212 to match the spec ceiling for formats 0/1.
…sages
ZIP-32 §6.1 seed fingerprint:
SeedFingerprint := BLAKE2b-256("Zcash_HD_Seed_FP", seed)
A 32-byte stable identity of the device's seed. Adds optional bytes
seed_fingerprint fields across the existing zcash messages so hosts
and devices can bind FVKs, addresses, and signing sessions to a
specific seed identity.
Four new fields, all optional, fully backward compatible:
ZcashOrchardFVK.seed_fingerprint (4)
Returned alongside (ak, nk, rivk). Lets a host pin an FVK to
this device's seed.
ZcashAddress.seed_fingerprint (2)
Returned alongside the confirmed UA after on-device verification.
Lets a host record "this address is on this device's seed."
ZcashSignPCZT.expected_seed_fingerprint (31)
Sent by host. If present, device checks against its own
fingerprint and rejects with Failure on mismatch before signing.
Mirrors Keystone3's PCZT zip32_derivation seed_fingerprint check
at the session level (one tx = one seed, no per-action duplication
needed for our flow).
ZcashDisplayAddress.expected_seed_fingerprint (7)
Sent by host. Same rejection semantics as above before displaying.
Matching nanopb max_size:32 entries added to messages-zcash.options.
No existing fields modified. Devices and hosts that don't populate
the new fields continue to work unchanged.
Brings in upstream's 7.14.0 release + features/7.15 commits:
d0b8d80 feat: 7.14.0 protocol — BIP-85, EVM metadata, Solana, TRON, TON, Zcash
18bb4a7 Merge pull request #100 from keepkey/release/7.14.0
bbcfcb0 feat: add ZcashDisplayAddress protocol messages (IDs 1308-1309)
bf8646b Merge pull request #101 from keepkey/features/7.15
Note: ZcashDisplayAddress was developed in parallel on both sides.
Conflict resolution prefers upstream's version (max_size:256 for the
unified-address fields, more correct than fork's :128 since UAs can be
long when shielded receivers are present).
# Conflicts:
# messages-zcash.options
# messages-zcash.proto
# messages.proto
# package.json
Brings in TRON/TON/Solana message-signing proto definitions:
0e3dc97 feat(tron): TIP-191 SignMessage, VerifyMessage, TIP-712 SignTypedHash
20e646a feat(ton): Ed25519 SignMessage primitive
c0ef415 feat(solana): SignOffchainMessage with domain-separated envelope
After this merge, fork master is the single source of truth that
firmware branches pin to during fork-only testing. A clean upstream
PR can be assembled later by cherry-picking these 3 commits onto a
fresh branch off keepkey/master.
Field comments documented the formula as
BLAKE2b-256("Zcash_HD_Seed_FP", seed)
but ZIP-32 §6.1 (and the actual conforming implementations in the
upstream zip32 Rust crate, keystone3-firmware, and our own firmware)
prepend a 1-byte length:
BLAKE2b-256("Zcash_HD_Seed_FP", I2LEBSP_8(len(seed)) || seed)
A host implementer following the proto comments would compute the
wrong fingerprint and have the device reject every signing/display
request with "seed fingerprint mismatch."
Comment-only change. No wire-format impact.
Remove fields 3-6 (address, ak, nk, rivk) from ZcashDisplayAddress.
Field numbers are reserved to prevent reuse. The on-device UA
derivation (Sinsemilla + SWU hash-to-curve) shipped — FVK-match
attestation against a host-built UA is strictly weaker than
device-derived display and is no longer supported.
What stays: address_n / account / expected_seed_fingerprint.
What ZcashAddress returns: address (now device-derived) + seed_fingerprint.
Add optional string memo field (field 7) to RippleSignTx protobuf message.
This enables THORChain swap routing memos and other arbitrary memo data
to be included in XRP transactions signed by the device.
Adds messages-hive.proto with HiveGetPublicKey, HivePublicKey,
HiveSignTx, and HiveSignedTx. Assigns message type IDs 1600-1603
in messages.proto.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* release: device-protocol 7.14.1
* feat(tron): add SignMessage (TIP-191), VerifyMessage, SignTypedHash (TIP-712)
Adds proto definitions for TRON message-signing parity:
- TronSignMessage / TronMessageSignature (1404/1405) — TIP-191 personal_sign
- TronVerifyMessage (1406) — host-asserted signature verification
- TronSignTypedHash / TronTypedDataSignature (1407/1408) — TIP-712 hash mode
Mirrors the Ethereum personal_sign + EIP-712 hash-mode shape. Firmware
implementation will reuse the secp256k1 + keccak256 primitives already
present for Ethereum, swapping the message prefix to '\x19TRON Signed Message:\n'
for TIP-191 and using '\x19\x01' for TIP-712.
Reserves IDs 1404-1408 contiguous to existing TRON range (1400-1403).
* feat(ton): add SignMessage Ed25519 message-signing primitive
Adds TonSignMessage / TonMessageSignature (1504/1505) — basic Ed25519
arbitrary-bytes signing, mirroring SolanaSignMessage's shape.
This primitive lacks domain separation by design (raw Ed25519 over message
bytes). Firmware should gate it behind the AdvancedMode policy — same
fence used for SolanaSignMessage in fsm_msg_solana.h — until a TON
Connect ton_proof envelope is added as a separate proto.
Reserves IDs 1504-1505 contiguous to existing TON range (1500-1503).
* feat(solana): add SignOffchainMessage with domain-separated envelope
Adds SolanaSignOffchainMessage / SolanaOffchainMessageSignature (756/757)
implementing the Solana off-chain message spec:
'\xff' || 'solana offchain' || version || format || length || message
The '\xff' lead byte is invalid as a Solana transaction prefix, providing
the domain separation that plain SolanaSignMessage (754/755) lacks. With
this primitive, firmware can drop the AdvancedMode policy gate currently
required for SolanaSignMessage (fsm_msg_solana.h:461-472) for ASCII/UTF8
off-chain messages, since the envelope makes transaction-shaped attacks
impossible.
message_format values per spec:
0 = Restricted ASCII (max 1212 bytes) — display-renderable
1 = UTF-8 limited (max 1212 bytes) — display-renderable with care
2 = UTF-8 extended (max 65515) — blind-sign only
Reserves IDs 756-757 contiguous to existing Solana range (750-755).
Bumped message max_size to 1212 to match the spec ceiling for formats 0/1.
* feat(zcash): drop host-supplied UA from ZcashDisplayAddress
Remove fields 3-6 (address, ak, nk, rivk) from ZcashDisplayAddress.
Field numbers are reserved to prevent reuse. The on-device UA
derivation (Sinsemilla + SWU hash-to-curve) shipped — FVK-match
attestation against a host-built UA is strictly weaker than
device-derived display and is no longer supported.
What stays: address_n / account / expected_seed_fingerprint.
What ZcashAddress returns: address (now device-derived) + seed_fingerprint.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* docs: update SolanaSignOffchainMessage to reflect 1212 byte limit and drop format 2
Agent-Logs-Url: https://github.com/keepkey/device-protocol/sessions/880cd954-b4b2-4f87-af05-8d715e1e0dc4
Co-authored-by: pastaghost <62026038+pastaghost@users.noreply.github.com>
* feat(hive): add Hive blockchain message definitions
Adds messages-hive.proto with HiveGetPublicKey, HivePublicKey,
HiveSignTx, and HiveSignedTx. Assigns message type IDs 1600-1603
in messages.proto.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(hive): add messages-hive.proto to build, drop broken build:json step
build:json used pbjs v0.0.5 which cannot parse proto3 reserved fields (present
in zcash, cosmos, ethereum, etc). proto.json is unused by the vault — only
messages_pb.js is imported. Build now runs build:js + build:postprocess only.
* feat(hive): add HiveGetPublicKeys, HiveSignAccountCreate, HiveSignAccountUpdate + SLIP-0048 paths
---------
Co-authored-by: pastaghost <62026038+pastaghost@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
NearGetAddress, NearAddress, NearSignTx, NearSignedTx.
Ed25519 derivation m/44'/397'/0'. Implicit account = lowercase hex of
the 32-byte Ed25519 pubkey.
Numbered 1610-1613 to avoid colliding with Hive (1600-1609), which
landed on alpha after the original NEAR spike.
…oadcast (#35)
account_create is authorized on-chain by the creator (sponsor) account's active
authority, not by the new account. The device's owner-key signature here is a
proof-of-control attestation; the sponsor recovers the owner pubkey to verify
control, then rebuilds and signs the real account_create with the creator's
active key server-side. Comment-only — no wire or generated-code change.
Addresses review P1 on the (closed) feature/hive PR.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Signing trust and response-sequence documentation contradict the linked firmware and can mislead host implementations.
0 open findings
Previously missed (3)
In code that hasn't changed since last review
Clarify runtime-only trust model for ERC-7730 catalogs
docs/erc7730-compiled-format.md:32
The linked 7.15 firmware's erc7730_catalog.c::finish() calls verify_runtime_delegate(): it verifies the catalog signature using a user-loaded signer, not a KeepKey-root certificate, and does not verify the record's certificate-signature bytes. A root-certified catalog therefore still needs its signer loaded, and successful preload does not establish KeepKey certification. Make the trust-boundary section, envelope table and signature description consistently describe the implemented runtime-only trust model.
Certified Solana signing is unsupported in linked firmware
messages-solana.proto:123
The firmware linked in keepkey/keepkey-firmware#482 rejects every nonempty clearsign_certificate with Failure_UnexpectedMessage ("Certified Solana signing is unsupported") before processing the schema. A valid certificate and 0x80 signer IDs therefore cannot enable this flow. Mark this field and the certified path described above as schema-only for that release; supports_solana_lut_attestation must not be treated as support for certified signing.
Document dual terminal replies for Zcash PCZT signing
messages-zcash.proto:276
The linked firmware returns ZcashPCZTActionAck(0) after the last transparent input when shielded actions remain. It withholds transparent signatures until the final shielded action passes validation, then sends ZcashTransparentSigned followed immediately by ZcashSignedPCZT. Transparent-only transactions also receive both terminal replies. Document this sequence so a v2 host does not wait for signatures before sending actions or leave the second reply unread.
Addressed the three body-only findings from review 5528118531 in cd62d20:
ERC-7730 now documents verification against a user-loaded runtime signer, the unchecked certificate-signature bytes, and the fact that preload does not confer KeepKey-root certification.
Solana now marks the certificate path as schema-only for 7.15 and states that nonempty certificates are rejected; LUT-attestation capability does not imply certified signing.
Zcash now documents the action request after transparent inputs, deferred signature release, and both terminal replies (including transparent-only transactions).
Checked these descriptions against the integrated 7.15 handlers. Protocol descriptors generated before and after the edit are byte-identical (SHA-256 1e0ac51572771b63c33f6442a358e69d6bd7292a7d5587fb24a664cf98c08b6f). These changes affect comments and documentation only.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Security-sensitive signing contracts and breaking Zcash interoperability require cross-repository human review, alongside correction of the retained binding issue.
Firmware 7.15's formatter validation requires both value and token roles for formatter kind 3. A compiler following this paragraph would therefore produce a definition rejected at preload. Document the required token role and lower tokenless descriptors to raw formatter kind 1, as the linked Python compiler already does.
Correct documented ABI nesting and path execution limits
docs/erc7730-compiled-format.md:306
These advertised execution limits exceed those enforced by the linked release: ABI nesting is limited to 8 levels including the root, and erc7730_cap_path() rejects 8 or more steps. The Python compiler enforces both bounds. Definitions using the documented 12-level nesting or 16-step paths will be rejected. Distinguish the wire format's capacity from firmware's executable limits.
Addressed both body-only findings from review 5530118906 in 8ba3985: formatter kind 3 requires value and token roles; tokenless descriptors lower to raw kind 1. The execution limits now state 8 ABI levels including the root and fewer than 8 path steps, separately from wire capacity. Checked against erc7730_capabilities.c, ERC7730_ABI_MAX_DEPTH, and the compiler. This commit changes documentation only.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Security-sensitive signing contracts and the breaking Zcash migration require final human validation against companion firmware and clients.
0 open findings
Previously missed (2)
In code that hasn't changed since last review
Document firmware 7.15 opcode subset and reject unsupported descriptors
docs/erc7730-compiled-format.md:303
The linked 7.15 firmware's erc7730_capabilities.h permits only condition opcode 3, path-step opcodes 1–2, formatter kinds 1–8/10/13, and display opcodes 1–8/10. Several operations described above therefore produce definitions that firmware refuses even when all listed numeric limits are met. Document the executable 7.15 subset separately from the broader wire grammar so host compilers can reject unsupported descriptors before preload.
Prevent silently ignoring removed fields in v1 address requests
messages-zcash.proto:36
Reserving protobuf tags prevents reuse, not receipt of unknown fields. The linked firmware decodes requests with pb_decode, and fsm_msgZcashDisplayAddress checks the account/path and optional seed fingerprint but cannot inspect the removed fields. An otherwise valid v1 request can therefore succeed while its supplied address/FVK is ignored, rather than returning Failure. Correct this migration guarantee and tell hosts to compare the returned address with their intended address.
Addressed the two body-only findings in review 5530256418 with 6fd3e27. The ERC-7730 guide now separates 7.15 executable opcodes, formatters, paths, and containers from the wire grammar and points compilers to device_refusal(). Zcash migration notes now explain unknown-field skipping and require hosts to compare the returned address with their intended address. Zcash contract checks pass; all protocol descriptors are byte-identical to 8ba3985 (SHA-256 c0c27769b18815dc2952eef759b45a819631ee049c85df11baf815624fd0ffe8). This documentation-only follow-up leaves the frozen firmware/client pins at 8ba3985; production dependency merges and repinning remain a later release gate.
keepkey/device-protocol#112 merged as bd34091. Same tree as the
previous pin 6fd3e27, so no generated code changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds protocol definitions for firmware 7.15: capability reporting, Taproot and dice modes, Ethereum runtime signers, streamed EIP-712, ERC-7730 definitions, Hive messages, NEAR schemas, Solana attestations, certified contacts, and Zcash wire v2 with breaking changes to batched transparent signatures. NEAR remains schema-only; firmware 7.15 has no handler.
EthereumClearSignDefinitionRequest.chain_iduses strings in generated JavaScript bindings to preserve the full uint64 range. Regressions check exact serialization and decoding through the maximum uint64 value. Documentation now specifies firmware 7.15's executable ERC-7730 subset, formatter roles and limits, and explains that legacy Zcash address tags are ignored: hosts must compare the returned address with the intended address.Validation: Protocol CI passed at
6fd3e2700a175f80ad678432d9ca939d44a3f695, including package/binding validation, descriptor compilation and the Zcash wire-contract check.Currently pinned by Python #197 at
45e2651a2and the int12 firmware fork candidates. Updates for upstream firmware #483 and #477–#482 are staged locally and remain unpushed. Human review remains required.