From f9e608196cd18d9649554ff4c9374364b966f5e5 Mon Sep 17 00:00:00 2001 From: highlander Date: Tue, 30 Jun 2026 00:47:24 -0500 Subject: [PATCH 1/2] feat: protocol additions for the firmware 7.x release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the device-protocol messages required by the upcoming firmware release: - thorchain: ThorchainMsgSend.denom (field 11) — non-RUNE assets (TCY, RUJI, IBC) - ripple: RippleSignTx.memo (field 7) — XRP->THORChain swap routing - hive: full Hive support — HiveGetPublicKey(s), HiveSignTx, HiveSignAccountCreate/Update (MessageType 1600-1609) - zcash: clear-signing + Orchard shielded protocol (transparent in/out/ack, PCZT, FVK, display-address) All additions are new optional fields / new message types — additive and backward-compatible. lib/ bindings are gitignored build artifacts; package.json build:js/json updated to include messages-hive.proto. --- messages-hive.options | 46 ++++++++++++ messages-hive.proto | 149 +++++++++++++++++++++++++++++++++++++++ messages-ripple.proto | 1 + messages-thorchain.proto | 1 + messages-zcash.options | 16 +++-- messages-zcash.proto | 120 +++++++++++++++++++++++-------- messages.proto | 16 ++++- package.json | 4 +- 8 files changed, 317 insertions(+), 36 deletions(-) create mode 100644 messages-hive.options create mode 100644 messages-hive.proto diff --git a/messages-hive.options b/messages-hive.options new file mode 100644 index 00000000..e878f3e3 --- /dev/null +++ b/messages-hive.options @@ -0,0 +1,46 @@ +HiveGetPublicKey.address_n max_count:8 + +HivePublicKey.public_key max_size:64 +HivePublicKey.raw_public_key max_size:33 + +HiveGetPublicKeys.account_index int_size:IS_32 + +HivePublicKeys.owner_key max_size:64 +HivePublicKeys.active_key max_size:64 +HivePublicKeys.memo_key max_size:64 +HivePublicKeys.posting_key max_size:64 + +HiveSignTx.address_n max_count:8 +HiveSignTx.chain_id max_size:32 +HiveSignTx.from max_size:16 +HiveSignTx.to max_size:16 +HiveSignTx.amount int_size:IS_64 +HiveSignTx.asset_symbol max_size:10 +HiveSignTx.memo max_size:2048 + +HiveSignedTx.signature max_size:65 +HiveSignedTx.serialized_tx max_size:512 + +HiveSignAccountCreate.address_n max_count:8 +HiveSignAccountCreate.chain_id max_size:32 +HiveSignAccountCreate.creator max_size:16 +HiveSignAccountCreate.new_account_name max_size:16 +HiveSignAccountCreate.owner_key max_size:64 +HiveSignAccountCreate.active_key max_size:64 +HiveSignAccountCreate.posting_key max_size:64 +HiveSignAccountCreate.memo_key max_size:64 +HiveSignAccountCreate.fee_amount int_size:IS_64 + +HiveSignedAccountCreate.signature max_size:65 +HiveSignedAccountCreate.serialized_tx max_size:512 + +HiveSignAccountUpdate.address_n max_count:8 +HiveSignAccountUpdate.chain_id max_size:32 +HiveSignAccountUpdate.account max_size:16 +HiveSignAccountUpdate.new_owner_key max_size:64 +HiveSignAccountUpdate.new_active_key max_size:64 +HiveSignAccountUpdate.new_posting_key max_size:64 +HiveSignAccountUpdate.new_memo_key max_size:64 + +HiveSignedAccountUpdate.signature max_size:65 +HiveSignedAccountUpdate.serialized_tx max_size:512 diff --git a/messages-hive.proto b/messages-hive.proto new file mode 100644 index 00000000..7612ec47 --- /dev/null +++ b/messages-hive.proto @@ -0,0 +1,149 @@ +syntax = "proto2"; + +option java_package = "com.shapeshift.keepkey.lib.protobuf"; +option java_outer_classname = "KeepKeyMessageHive"; + +/** + * Request: Ask device for a single Hive public key at a given SLIP-0048 path. + * Path format: m/48'/13'/role'/account'/0' + * role: 0'=owner 1'=active 3'=memo 4'=posting + * @start + * @next HivePublicKey + * @next Failure + */ +message HiveGetPublicKey { + repeated uint32 address_n = 1; // Full SLIP-0048 path (all 5 components hardened) + optional bool show_display = 2; // Confirm on device before returning + optional uint32 role = 3; // 0=owner 1=active 3=memo 4=posting (for display label only) +} + +/** + * Response: Single Hive public key + * @end + */ +message HivePublicKey { + optional string public_key = 1; // STM-prefixed base58check public key + optional bytes raw_public_key = 2; // 33-byte compressed secp256k1 public key +} + +/** + * Request: Ask device for all four Hive role keys in one interaction. + * Derives owner/active/memo/posting keys for the given account index. + * Paths: + * owner: m/48'/13'/0'/account_index'/0' + * active: m/48'/13'/1'/account_index'/0' + * memo: m/48'/13'/3'/account_index'/0' + * posting: m/48'/13'/4'/account_index'/0' + * @start + * @next HivePublicKeys + * @next Failure + */ +message HiveGetPublicKeys { + optional uint32 account_index = 1 [default = 0]; // Hive account slot (0 = first account) + optional bool show_display = 2; // Confirm on device before returning +} + +/** + * Response: All four Hive role public keys + * @end + */ +message HivePublicKeys { + optional string owner_key = 1; // STM... owner public key + optional string active_key = 2; // STM... active public key + optional string memo_key = 3; // STM... memo public key + optional string posting_key = 4; // STM... posting public key +} + +/** + * Request: Sign a Hive transfer transaction (op type 2). + * Signing key should be the active key: m/48'/13'/1'/account'/0' + * @start + * @next HiveSignedTx + * @next Failure + */ +message HiveSignTx { + repeated uint32 address_n = 1; // Full SLIP-0048 path of signing key + optional bytes chain_id = 2; // 32-byte chain ID (mainnet = beeab0de...) + optional uint32 ref_block_num = 3; // Reference block number (uint16) + optional uint32 ref_block_prefix = 4; // Reference block prefix (uint32) + optional uint32 expiration = 5; // Expiration Unix timestamp (uint32) + optional string from = 6; // Sender account name + optional string to = 7; // Recipient account name + optional uint64 amount = 8; // Amount in milliHIVE (1000 = 1.000 HIVE) + optional uint32 decimals = 9; // Decimal places (3 for HIVE/HBD) + optional string asset_symbol = 10; // "HIVE" or "HBD" + optional string memo = 11; // Optional transfer memo +} + +/** + * Response: Signed Hive transfer transaction + * @end + */ +message HiveSignedTx { + optional bytes signature = 1; // 65-byte recoverable secp256k1 signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} + +/** + * Request: Sign a Hive account_create operation (op type 9). + * All four role public keys become the account authorities at genesis. + * No software keys are generated. KeepKey is sole root of trust from block 1. + * Signing key: owner key at m/48'/13'/0'/account_index'/0' + * @start + * @next HiveSignedAccountCreate + * @next Failure + */ +message HiveSignAccountCreate { + repeated uint32 address_n = 1; // Owner key path (m/48'/13'/0'/account'/0') + optional bytes chain_id = 2; // 32-byte chain ID + optional uint32 ref_block_num = 3; + optional uint32 ref_block_prefix = 4; + optional uint32 expiration = 5; + optional string creator = 6; // Pioneer sponsor account name + optional string new_account_name = 7; // Desired Hive username + optional string owner_key = 8; // STM... owner public key (from device) + optional string active_key = 9; // STM... active public key (from device) + optional string posting_key = 10; // STM... posting public key (from device) + optional string memo_key = 11; // STM... memo public key (from device) + optional uint64 fee_amount = 12; // Creation fee in milliHIVE (3000 = 3.000 HIVE) +} + +/** + * Response: Signed Hive account_create transaction + * @end + */ +message HiveSignedAccountCreate { + optional bytes signature = 1; // 65-byte recoverable signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} + +/** + * Request: Sign a Hive account_update operation (op type 10). + * Replaces all account authorities with KeepKey-derived keys. + * Used to secure an existing Hive account. + * Signing key: owner key at m/48'/13'/0'/account_index'/0' + * @start + * @next HiveSignedAccountUpdate + * @next Failure + */ +message HiveSignAccountUpdate { + repeated uint32 address_n = 1; // Owner key path (must match account's current owner) + optional bytes chain_id = 2; // 32-byte chain ID + optional uint32 ref_block_num = 3; + optional uint32 ref_block_prefix = 4; + optional uint32 expiration = 5; + optional string account = 6; // Hive account name to update + optional string new_owner_key = 7; // STM... new owner public key + optional string new_active_key = 8; // STM... new active public key + optional string new_posting_key = 9; // STM... new posting public key + optional string new_memo_key = 10; // STM... new memo public key +} + +/** + * Response: Signed Hive account_update transaction + * @end + */ +message HiveSignedAccountUpdate { + optional bytes signature = 1; // 65-byte recoverable signature + optional bytes serialized_tx = 2; // Serialized Graphene transaction bytes +} diff --git a/messages-ripple.proto b/messages-ripple.proto index 0fc012d2..bf526ef7 100644 --- a/messages-ripple.proto +++ b/messages-ripple.proto @@ -34,6 +34,7 @@ message RippleSignTx { optional uint32 sequence = 4; // transaction sequence number optional uint32 last_ledger_sequence = 5; // see https://developers.ripple.com/reliable-transaction-submission.html#lastledgersequence optional RipplePayment payment = 6; // Payment transaction type + optional string memo = 7; // transaction memo (e.g. THORChain swap routing memo) } /** diff --git a/messages-thorchain.proto b/messages-thorchain.proto index acde357a..00183623 100644 --- a/messages-thorchain.proto +++ b/messages-thorchain.proto @@ -60,6 +60,7 @@ message ThorchainMsgSend { optional uint64 amount = 8 [jstype = JS_STRING]; optional OutputAddressType address_type = 9; reserved 10; + optional string denom = 11; // asset denom, e.g. "rune" or IBC denom } message ThorchainMsgDeposit { diff --git a/messages-zcash.options b/messages-zcash.options index 89fcdc36..2ebcb224 100644 --- a/messages-zcash.options +++ b/messages-zcash.options @@ -5,6 +5,7 @@ ZcashSignPCZT.transparent_digest max_size:32 ZcashSignPCZT.sapling_digest max_size:32 ZcashSignPCZT.orchard_digest max_size:32 ZcashSignPCZT.orchard_anchor max_size:32 +ZcashSignPCZT.expected_seed_fingerprint max_size:32 ZcashPCZTAction.alpha max_size:32 ZcashPCZTAction.sighash max_size:32 @@ -17,6 +18,8 @@ ZcashPCZTAction.enc_memo max_size:512 ZcashPCZTAction.enc_noncompact max_size:612 ZcashPCZTAction.rk max_size:32 ZcashPCZTAction.out_ciphertext max_size:80 +ZcashPCZTAction.recipient max_size:43 +ZcashPCZTAction.rseed max_size:32 ZcashSignedPCZT.signatures max_count:64 max_size:64 ZcashSignedPCZT.txid max_size:32 @@ -26,16 +29,19 @@ ZcashGetOrchardFVK.address_n max_count:8 ZcashOrchardFVK.ak max_size:32 ZcashOrchardFVK.nk max_size:32 ZcashOrchardFVK.rivk max_size:32 +ZcashOrchardFVK.seed_fingerprint max_size:32 + +ZcashTransparentOutput.script_pubkey max_size:128 ZcashTransparentInput.sighash max_size:32 ZcashTransparentInput.address_n max_count:8 +ZcashTransparentInput.prevout_txid max_size:32 +ZcashTransparentInput.script_pubkey max_size:128 -ZcashTransparentSig.signature max_size:73 +ZcashTransparentSigned.signatures max_count:8 max_size:73 ZcashDisplayAddress.address_n max_count:8 -ZcashDisplayAddress.address max_size:256 -ZcashDisplayAddress.ak max_size:32 -ZcashDisplayAddress.nk max_size:32 -ZcashDisplayAddress.rivk max_size:32 +ZcashDisplayAddress.expected_seed_fingerprint max_size:32 ZcashAddress.address max_size:256 +ZcashAddress.seed_fingerprint max_size:32 diff --git a/messages-zcash.proto b/messages-zcash.proto index e6e14445..c9659dd3 100644 --- a/messages-zcash.proto +++ b/messages-zcash.proto @@ -18,6 +18,7 @@ option java_outer_classname = "KeepKeyMessageZcash"; * The device derives spend authorization keys, computes the sighash, * and returns RedPallas signatures for each Orchard action. * + * @next ZcashTransparentAck * @next ZcashPCZTActionAck * @next Failure */ @@ -32,14 +33,26 @@ message ZcashSignPCZT { // Phase 2a: sub-digests for on-device sighash computation optional bytes header_digest = 8; // 32-byte pre-computed header digest optional bytes transparent_digest = 9; // 32-byte transparent digest (or empty) - optional bytes sapling_digest = 10; // 32-byte sapling digest (or empty) + optional bytes sapling_digest = 10; // Reserved for future Sapling support; currently rejected optional bytes orchard_digest = 11; // 32-byte orchard digest // Phase 2b: bundle metadata for orchard digest verification optional uint32 orchard_flags = 12; // Orchard bundle flags byte optional int64 orchard_value_balance = 13; // Orchard value balance (LE i64) optional bytes orchard_anchor = 14; // 32-byte orchard anchor + // Phase 4: plaintext header fields for on-device header digest verification + optional uint32 tx_version = 15; // Transaction version (without overwinter bit) + optional uint32 version_group_id = 16; // Version group ID + optional uint32 lock_time = 17; // Transaction lock time + optional uint32 expiry_height = 18; // Transaction expiry height // Phase 3: transparent shielding support + optional uint32 n_transparent_outputs = 29; // 0 for shielded-only (default) optional uint32 n_transparent_inputs = 30; // 0 for shielded-only (default), >0 for hybrid shielding tx + // Seed identity binding (ZIP-32 §6.1) + optional bytes expected_seed_fingerprint = 31; // 32-byte ZIP-32 §6.1 seed fingerprint: + // BLAKE2b-256("Zcash_HD_Seed_FP", + // I2LEBSP_8(len(seed)) || seed) + // If present, device verifies match against its own + // seed fingerprint and rejects with Failure on mismatch. } /** @@ -66,6 +79,11 @@ message ZcashPCZTAction { optional bytes enc_noncompact = 12; // Remaining encrypted note bytes optional bytes rk = 13; // 32-byte randomized verification key optional bytes out_ciphertext = 14; // 80-byte output ciphertext + // Phase 4: plaintext Orchard output metadata for trusted display. + // Firmware recomputes cmx from recipient/value/rseed and nullifier before + // displaying the receiver/value and before emitting any signature. + optional bytes recipient = 15; // 43-byte Orchard receiver: d || pk_d + optional bytes rseed = 16; // 32-byte output note rseed } /** @@ -116,64 +134,110 @@ message ZcashOrchardFVK { optional bytes ak = 1; // 32-byte authorizing key (Pallas point) optional bytes nk = 2; // 32-byte nullifier deriving key optional bytes rivk = 3; // 32-byte commitment randomness key + optional bytes seed_fingerprint = 4; // 32-byte ZIP-32 §6.1 seed fingerprint: + // BLAKE2b-256("Zcash_HD_Seed_FP", + // I2LEBSP_8(len(seed)) || seed) + // Stable identity of the device's seed; lets a host pin an FVK + // to a specific seed across sessions. +} + +/** + * Request: Transparent output data for hybrid transactions. + * Sent before transparent inputs so the device can review standard + * transparent recipients before any signature is emitted. + * + * @next ZcashTransparentAck + * @next ZcashPCZTActionAck + * @next Failure + */ +message ZcashTransparentOutput { + required uint32 index = 1; // Output index within the transaction + optional uint64 amount = 2; // Output value in zatoshis + optional bytes script_pubkey = 3; // Standard P2PKH/P2SH scriptPubKey } /** * Request: Transparent input data for hybrid shielding transactions. - * Sent one per transparent input during the transparent signing phase. - * The device ECDSA-signs the per-input sighash with the secp256k1 key - * at the provided BIP44 path. + * Sent after all transparent outputs have been streamed. * - * Flow: after ZcashSignPCZT with n_transparent_inputs > 0, the device - * responds with ZcashPCZTActionAck. For each transparent input, the host - * sends ZcashTransparentInput and receives ZcashTransparentSig. After - * all transparent inputs, the device transitions to the Orchard phase. + * The device stores every input first because ZIP-244 per-input transparent + * sighashes commit to all transparent prevouts, values, scripts, sequences, + * and outputs. Host-provided sighash is legacy and rejected when present. * - * @next ZcashTransparentSig + * @next ZcashTransparentAck + * @next ZcashTransparentSigned * @next Failure */ message ZcashTransparentInput { required uint32 index = 1; // Input index within the transaction - required bytes sighash = 2; // 32-byte per-input sighash (host-computed, ZIP-244) + optional bytes sighash = 2; // Legacy host-computed sighash; rejected when present repeated uint32 address_n = 3; // BIP44 path [44', 133', 0', 0, 0] - optional uint64 amount = 4; // Input value in zatoshis (for display verification) + optional uint64 amount = 4; // Input value in zatoshis + optional bytes prevout_txid = 5; // Previous transaction ID + optional uint32 prevout_index = 6; // Previous output index + optional uint32 sequence = 7; // Input sequence + optional bytes script_pubkey = 8; // Previous output scriptPubKey +} + +/** + * Response: Acknowledgment requesting the next transparent item. + * + * @prev ZcashSignPCZT + * @prev ZcashTransparentOutput + * @prev ZcashTransparentInput + */ +message ZcashTransparentAck { + optional uint32 next_output_index = 1; // Next transparent output index + optional uint32 next_input_index = 2; // Next transparent input index } /** - * Response: ECDSA signature for a transparent input. + * Response: ECDSA signatures for transparent inputs. * * @prev ZcashTransparentInput */ -message ZcashTransparentSig { - required bytes signature = 1; // DER ECDSA signature (72-73 bytes) - optional uint32 next_index = 2; // Next transparent input index, or 0xFF = done +message ZcashTransparentSigned { + repeated bytes signatures = 1; // DER ECDSA signatures, one per transparent input } /** - * Request: Display and verify a Zcash unified address on device. + * Request: Display the device-derived Orchard unified address on screen. * - * The host provides the unified address string and the FVK components - * (ak, nk, rivk). The device re-derives its own Orchard keys from seed - * and compares them against the provided FVK to verify the Orchard - * receiver belongs to this device. + * The device derives the Orchard-only Unified Address (Sinsemilla + SWU + * hash-to-curve, default diversifier index 0) from its own seed at the + * requested account and shows it on the OLED with a QR code. What appears + * on screen is bound to this device — there is no host-supplied address + * to validate. + * + * Either account or a complete address_n path (m/32'/133'/account', all + * hardened) is REQUIRED. The device rejects requests that omit both. + * + * Fields 3–6 (host-supplied address, ak, nk, rivk) were removed when the + * device gained on-device UA derivation: FVK-match attestation against a + * host-built UA is strictly weaker than device-derived display and was + * dropped. Field numbers are reserved to prevent reuse. * * @next ZcashAddress * @next Failure */ message ZcashDisplayAddress { - repeated uint32 address_n = 1; // ZIP-32 derivation path [32', 133', account'] - optional uint32 account = 2; // Account index (alternative to full path) - optional string address = 3; // Unified address string (u1...) - optional bytes ak = 4; // 32-byte authorizing key for verification - optional bytes nk = 5; // 32-byte nullifier deriving key for verification - optional bytes rivk = 6; // 32-byte commitment randomness key for verification + reserved 3, 4, 5, 6; + reserved "address", "ak", "nk", "rivk"; + repeated uint32 address_n = 1; // ZIP-32 path [32', 133', account'] — required if account omitted + optional uint32 account = 2; // Account index — required if address_n omitted + optional bytes expected_seed_fingerprint = 7; // 32-byte ZIP-32 §6.1 seed fingerprint. + // If present, device verifies match against its own + // seed fingerprint and rejects with Failure on mismatch. } /** - * Response: Verified Zcash address. + * Response: Confirmed Zcash address after user approval on device. * * @prev ZcashDisplayAddress */ message ZcashAddress { - optional string address = 1; // Verified unified address string + optional string address = 1; // Confirmed unified address + optional bytes seed_fingerprint = 2; // 32-byte ZIP-32 §6.1 seed fingerprint of the attesting + // device. Returned alongside the confirmed address so a host + // can record that this UA is bound to this device's seed. } diff --git a/messages.proto b/messages.proto index ca35898c..1a5466af 100644 --- a/messages.proto +++ b/messages.proto @@ -217,9 +217,11 @@ enum MessageType { MessageType_ZcashGetOrchardFVK = 1304 [ (wire_in) = true ]; MessageType_ZcashOrchardFVK = 1305 [ (wire_out) = true ]; MessageType_ZcashTransparentInput = 1306 [ (wire_in) = true ]; - MessageType_ZcashTransparentSig = 1307 [ (wire_out) = true ]; + MessageType_ZcashTransparentSigned = 1307 [ (wire_out) = true ]; MessageType_ZcashDisplayAddress = 1308 [ (wire_in) = true ]; MessageType_ZcashAddress = 1309 [ (wire_out) = true ]; + MessageType_ZcashTransparentOutput = 1310 [ (wire_in) = true ]; + MessageType_ZcashTransparentAck = 1311 [ (wire_out) = true ]; // TRON MessageType_TronGetAddress = 1400 [ (wire_in) = true ]; @@ -239,6 +241,18 @@ enum MessageType { MessageType_TonSignedTx = 1503 [ (wire_out) = true ]; MessageType_TonSignMessage = 1504 [ (wire_in) = true ]; MessageType_TonMessageSignature = 1505 [ (wire_out) = true ]; + + // Hive + MessageType_HiveGetPublicKey = 1600 [ (wire_in) = true ]; + MessageType_HivePublicKey = 1601 [ (wire_out) = true ]; + MessageType_HiveSignTx = 1602 [ (wire_in) = true ]; + MessageType_HiveSignedTx = 1603 [ (wire_out) = true ]; + MessageType_HiveGetPublicKeys = 1604 [ (wire_in) = true ]; + MessageType_HivePublicKeys = 1605 [ (wire_out) = true ]; + MessageType_HiveSignAccountCreate = 1606 [ (wire_in) = true ]; + MessageType_HiveSignedAccountCreate = 1607 [ (wire_out) = true ]; + MessageType_HiveSignAccountUpdate = 1608 [ (wire_in) = true ]; + MessageType_HiveSignedAccountUpdate = 1609 [ (wire_out) = true ]; } //////////////////// diff --git a/package.json b/package.json index 51f6d535..9e82e419 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "scripts": { "clean": "rm -rf ./lib/*.js ./lib/*.ts", "build": "npm run build:js && npm run build:json && npm run build:postprocess", - "build:js": "protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:./lib --ts_out=./lib types.proto messages.proto messages-ethereum.proto messages-eos.proto messages-nano.proto messages-cosmos.proto messages-binance.proto messages-ripple.proto messages-tendermint.proto messages-thorchain.proto messages-osmosis.proto messages-mayachain.proto messages-solana.proto messages-tron.proto messages-ton.proto messages-zcash.proto", - "build:json": "pbjs --keep-case -t json ./types.proto ./messages.proto ./messages-ethereum.proto ./messages-eos.proto ./messages-nano.proto ./messages-cosmos.proto ./messages-binance.proto ./messages-ripple.proto ./messages-tendermint.proto ./messages-thorchain.proto ./messages-osmosis.proto ./messages-mayachain.proto ./messages-solana.proto ./messages-tron.proto ./messages-ton.proto ./messages-zcash.proto > ./lib/proto.json", + "build:js": "protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --js_out=import_style=commonjs,binary:./lib --ts_out=./lib types.proto messages.proto messages-ethereum.proto messages-eos.proto messages-nano.proto messages-cosmos.proto messages-binance.proto messages-ripple.proto messages-tendermint.proto messages-thorchain.proto messages-osmosis.proto messages-mayachain.proto messages-solana.proto messages-tron.proto messages-ton.proto messages-zcash.proto messages-hive.proto", + "build:json": "pbjs --keep-case -t json ./types.proto ./messages.proto ./messages-ethereum.proto ./messages-eos.proto ./messages-nano.proto ./messages-cosmos.proto ./messages-binance.proto ./messages-ripple.proto ./messages-tendermint.proto ./messages-thorchain.proto ./messages-osmosis.proto ./messages-mayachain.proto ./messages-solana.proto ./messages-tron.proto ./messages-ton.proto ./messages-zcash.proto ./messages-hive.proto > ./lib/proto.json", "build:postprocess": "find ./lib -name \"*.js\" -exec sed -i '' -e \"s/var global = Function(\\'return this\\')();/var global = (function(){ return this }).call(null);/g\" {} \\;", "prepublishOnly": "npm run build", "test": "echo \"Error: no test specified\" && exit 1" From 2ec999a9b2e5174da5981e85f66845a97cdaa877 Mon Sep 17 00:00:00 2001 From: highlander Date: Thu, 2 Jul 2026 02:10:27 -0500 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20LoadClearsignSigner=20(117)=20?= =?UTF-8?q?=E2=80=94=20runtime=20clearsign=20signer=20with=20alias,=20user?= =?UTF-8?q?-confirmed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages-ethereum.options | 2 ++ messages-ethereum.proto | 16 ++++++++++++++++ messages.proto | 1 + 3 files changed, 19 insertions(+) diff --git a/messages-ethereum.options b/messages-ethereum.options index 1759d0ac..9cd03b4f 100644 --- a/messages-ethereum.options +++ b/messages-ethereum.options @@ -1,2 +1,4 @@ EthereumTxMetadata.signed_payload max_size:1024 EthereumMetadataAck.display_summary max_size:32 +LoadClearsignSigner.pubkey max_size:33 +LoadClearsignSigner.alias max_size:32 diff --git a/messages-ethereum.proto b/messages-ethereum.proto index b8719d34..40e7925e 100644 --- a/messages-ethereum.proto +++ b/messages-ethereum.proto @@ -113,6 +113,22 @@ message EthereumMetadataAck { optional string display_summary = 2; // Brief result for host logging } +/** + * Request: Load a clearsign signer public key + alias into a runtime key slot. + * The device shows a mandatory confirmation (alias + key fingerprint) before + * accepting; there is no way to load a signer without user consent. Loaded + * signers live in RAM only and are cleared on reboot. Every transaction whose + * metadata was verified by a loaded (non built-in) signer is preceded by a + * warning screen naming the alias during transaction confirmation. + * @next Success + * @next Failure + */ +message LoadClearsignSigner { + optional uint32 key_id = 1; // target key slot (0-3); must not hold a built-in key + optional bytes pubkey = 2; // 33-byte compressed secp256k1 public key + optional string alias = 3; // short display name shown on load confirm + per-tx warning +} + //////////////////////////////////////// // Ethereum: Message signing messages // //////////////////////////////////////// diff --git a/messages.proto b/messages.proto index 1a5466af..2f8e5b30 100644 --- a/messages.proto +++ b/messages.proto @@ -100,6 +100,7 @@ enum MessageType { // Ethereum Clear Signing MessageType_EthereumTxMetadata = 115 [ (wire_in) = true ]; MessageType_EthereumMetadataAck = 116 [ (wire_out) = true ]; + MessageType_LoadClearsignSigner = 117 [ (wire_in) = true ]; // BIP-85 MessageType_GetBip85Mnemonic = 120 [ (wire_in) = true ];