diff --git a/build_pb.sh b/build_pb.sh index 4de4a02c..d5936b46 100755 --- a/build_pb.sh +++ b/build_pb.sh @@ -3,7 +3,7 @@ CURDIR=$(pwd) cd "device-protocol" echo "Building with protoc version: $(protoc --version)" -for i in messages messages-ethereum messages-eos messages-nano messages-cosmos messages-ripple messages-binance messages-tendermint messages-thorchain messages-osmosis messages-mayachain types ; do +for i in messages messages-ethereum messages-eos messages-nano messages-cosmos messages-ripple messages-binance messages-tendermint messages-thorchain messages-osmosis messages-mayachain messages-solana messages-zcash types ; do protoc --python_out=$CURDIR/keepkeylib/ -I/usr/include -I. $i.proto i=${i/-/_} sed -i -Ee 's/^import ([^.]+_pb2)/from . import \1/' $CURDIR/keepkeylib/"$i"_pb2.py diff --git a/device-protocol b/device-protocol index ce10ea79..1b4db72e 160000 --- a/device-protocol +++ b/device-protocol @@ -1 +1 @@ -Subproject commit ce10ea79a000f2e20e87fbbab3a0c4f7a07f6f0e +Subproject commit 1b4db72e4ad4d0dc619fe8ad2824cdd4a2698d3f diff --git a/keepkeylib/client.py b/keepkeylib/client.py index ecf837fb..55ab8dc6 100644 --- a/keepkeylib/client.py +++ b/keepkeylib/client.py @@ -45,6 +45,8 @@ from . import messages_tendermint_pb2 as tendermint_proto from . import messages_thorchain_pb2 as thorchain_proto from . import messages_mayachain_pb2 as mayachain_proto +from . import messages_solana_pb2 as solana_proto +from . import messages_zcash_pb2 as zcash_proto from . import types_pb2 as types from . import eos from . import nano @@ -1138,6 +1140,79 @@ def mayachain_sign_tx( return resp + # ── Solana ────────────────────────────────────────────────────── + + @field('address') + @expect(solana_proto.SolanaAddress) + def solana_get_address(self, address_n, show_display=False): + return self.call( + solana_proto.SolanaGetAddress(address_n=address_n, show_display=show_display) + ) + + @session + @expect(solana_proto.SolanaSignedTx) + def solana_sign_tx(self, address_n, raw_tx): + return self.call( + solana_proto.SolanaSignTx(address_n=address_n, raw_tx=raw_tx) + ) + + @session + @expect(solana_proto.SolanaMessageSignature) + def solana_sign_message(self, address_n, message): + return self.call( + solana_proto.SolanaSignMessage(address_n=address_n, message=message) + ) + + # ── Zcash Orchard (shielded) ───────────────────────────────────── + # See messages-zcash.proto for full message definitions. + + @session + @expect(zcash_proto.ZcashOrchardFVK) + def zcash_get_orchard_fvk(self, address_n, account=0, show_display=False): + return self.call( + zcash_proto.ZcashGetOrchardFVK( + address_n=address_n, + account=account, + show_display=show_display, + ) + ) + + @session + def zcash_sign_pczt(self, address_n, n_actions, total_amount, fee, + branch_id, header_digest, transparent_digest, + sapling_digest, orchard_digest, actions, + account=0, orchard_flags=None, + orchard_value_balance=None, orchard_anchor=None): + """Sign a Zcash Orchard PCZT. + + *actions* is a list of dicts, each passed to ZcashPCZTAction. + Returns ZcashSignedPCZT with .signatures and .txid. + """ + resp = self.call( + zcash_proto.ZcashSignPCZT( + address_n=address_n, + account=account, + n_actions=n_actions, + total_amount=total_amount, + fee=fee, + branch_id=branch_id, + header_digest=header_digest, + transparent_digest=transparent_digest, + sapling_digest=sapling_digest, + orchard_digest=orchard_digest, + orchard_flags=orchard_flags, + orchard_value_balance=orchard_value_balance, + orchard_anchor=orchard_anchor, + ) + ) + # Stream actions in response to ZcashPCZTActionAck + for action in actions: + if isinstance(resp, zcash_proto.ZcashPCZTActionAck): + resp = self.call(zcash_proto.ZcashPCZTAction(**action)) + else: + break + return resp + @field('address') @expect(ripple_proto.RippleAddress) def ripple_get_address(self, address_n, show_display=False): diff --git a/keepkeylib/mapping.py b/keepkeylib/mapping.py index 44338646..25c13691 100644 --- a/keepkeylib/mapping.py +++ b/keepkeylib/mapping.py @@ -9,6 +9,7 @@ from . import messages_tendermint_pb2 as tendermint_proto from . import messages_thorchain_pb2 as thorchain_proto from . import messages_mayachain_pb2 as mayachain_proto +from . import messages_solana_pb2 as solana_proto map_type_to_class = {} map_class_to_type = {} @@ -36,6 +37,8 @@ def build_map(): msg_class = getattr(thorchain_proto, msg_name) elif msg_type.startswith('MessageType_Mayachain'): msg_class = getattr(mayachain_proto, msg_name) + elif msg_type.startswith('MessageType_Solana'): + msg_class = getattr(solana_proto, msg_name) else: msg_class = getattr(proto, msg_name) diff --git a/keepkeylib/messages_pb2.py b/keepkeylib/messages_pb2.py index 65e0fcf1..d0024c83 100644 --- a/keepkeylib/messages_pb2.py +++ b/keepkeylib/messages_pb2.py @@ -21,7 +21,7 @@ name='messages.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xaa\x04\n\x08\x46\x65\x61tures\x12\x0e\n\x06vendor\x18\x01 \x01(\t\x12\x15\n\rmajor_version\x18\x02 \x01(\r\x12\x15\n\rminor_version\x18\x03 \x01(\r\x12\x15\n\rpatch_version\x18\x04 \x01(\r\x12\x17\n\x0f\x62ootloader_mode\x18\x05 \x01(\x08\x12\x11\n\tdevice_id\x18\x06 \x01(\t\x12\x16\n\x0epin_protection\x18\x07 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x08 \x01(\x08\x12\x10\n\x08language\x18\t \x01(\t\x12\r\n\x05label\x18\n \x01(\t\x12\x18\n\x05\x63oins\x18\x0b \x03(\x0b\x32\t.CoinType\x12\x13\n\x0binitialized\x18\x0c \x01(\x08\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x17\n\x0f\x62ootloader_hash\x18\x0e \x01(\x0c\x12\x10\n\x08imported\x18\x0f \x01(\x08\x12\x12\n\npin_cached\x18\x10 \x01(\x08\x12\x19\n\x11passphrase_cached\x18\x11 \x01(\x08\x12\x1d\n\x08policies\x18\x12 \x03(\x0b\x32\x0b.PolicyType\x12\r\n\x05model\x18\x15 \x01(\t\x12\x18\n\x10\x66irmware_variant\x18\x16 \x01(\t\x12\x15\n\rfirmware_hash\x18\x17 \x01(\x0c\x12\x11\n\tno_backup\x18\x18 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x19 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x1a \x01(\r\"*\n\x0cGetCoinTable\x12\r\n\x05start\x18\x01 \x01(\r\x12\x0b\n\x03\x65nd\x18\x02 \x01(\r\"L\n\tCoinTable\x12\x18\n\x05table\x18\x01 \x03(\x0b\x32\t.CoinType\x12\x11\n\tnum_coins\x18\x02 \x01(\r\x12\x12\n\nchunk_size\x18\x03 \x01(\r\"\x0e\n\x0c\x43learSession\"y\n\rApplySettings\x12\x10\n\x08language\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x16\n\x0euse_passphrase\x18\x03 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x04 \x01(\r\x12\x13\n\x0bu2f_counter\x18\x05 \x01(\r\"\x1b\n\tChangePin\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x87\x01\n\x04Ping\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x19\n\x11\x62utton_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x05 \x01(\x08\"\x1a\n\x07Success\x12\x0f\n\x07message\x18\x01 \x01(\t\"6\n\x07\x46\x61ilure\x12\x1a\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x0c.FailureType\x12\x0f\n\x07message\x18\x02 \x01(\t\"?\n\rButtonRequest\x12 \n\x04\x63ode\x18\x01 \x01(\x0e\x32\x12.ButtonRequestType\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x0b\n\tButtonAck\"7\n\x10PinMatrixRequest\x12#\n\x04type\x18\x01 \x01(\x0e\x32\x15.PinMatrixRequestType\"\x1b\n\x0cPinMatrixAck\x12\x0b\n\x03pin\x18\x01 \x02(\t\"\x08\n\x06\x43\x61ncel\"\x13\n\x11PassphraseRequest\"#\n\rPassphraseAck\x12\x12\n\npassphrase\x18\x01 \x02(\t\"\x1a\n\nGetEntropy\x12\x0c\n\x04size\x18\x01 \x02(\r\"\x1a\n\x07\x45ntropy\x12\x0f\n\x07\x65ntropy\x18\x01 \x02(\x0c\"\xa2\x01\n\x0cGetPublicKey\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x02 \x01(\t\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"4\n\tPublicKey\x12\x19\n\x04node\x18\x01 \x02(\x0b\x32\x0b.HDNodeType\x12\x0c\n\x04xpub\x18\x02 \x01(\t\"\xb3\x01\n\nGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1a\n\tcoin_name\x18\x02 \x01(\t:\x07\x42itcoin\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12+\n\x08multisig\x18\x04 \x01(\x0b\x32\x19.MultisigRedeemScriptType\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"\x1a\n\x07\x41\x64\x64ress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\t\"\x0c\n\nWipeDevice\"\xbb\x01\n\nLoadDevice\x12\x10\n\x08mnemonic\x18\x01 \x01(\t\x12\x19\n\x04node\x18\x02 \x01(\x0b\x32\x0b.HDNodeType\x12\x0b\n\x03pin\x18\x03 \x01(\t\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x15\n\rskip_checksum\x18\x07 \x01(\x08\x12\x13\n\x0bu2f_counter\x18\x08 \x01(\r\"\xe1\x01\n\x0bResetDevice\x12\x16\n\x0e\x64isplay_random\x18\x01 \x01(\x08\x12\x15\n\x08strength\x18\x02 \x01(\r:\x03\x32\x35\x36\x12\x1d\n\x15passphrase_protection\x18\x03 \x01(\x08\x12\x16\n\x0epin_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x11\n\tno_backup\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\"\x10\n\x0e\x45ntropyRequest\"\x1d\n\nEntropyAck\x12\x0f\n\x07\x65ntropy\x18\x01 \x01(\x0c\"\xff\x01\n\x0eRecoveryDevice\x12\x12\n\nword_count\x18\x01 \x01(\r\x12\x1d\n\x15passphrase_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x19\n\x08language\x18\x04 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x05 \x01(\t\x12\x18\n\x10\x65nforce_wordlist\x18\x06 \x01(\x08\x12\x1c\n\x14use_character_cipher\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x0f\n\x07\x64ry_run\x18\n \x01(\x08\"\r\n\x0bWordRequest\"\x17\n\x07WordAck\x12\x0c\n\x04word\x18\x01 \x02(\t\";\n\x10\x43haracterRequest\x12\x10\n\x08word_pos\x18\x01 \x02(\r\x12\x15\n\rcharacter_pos\x18\x02 \x02(\r\"?\n\x0c\x43haracterAck\x12\x11\n\tcharacter\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64one\x18\x03 \x01(\x08\"\x82\x01\n\x0bSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"`\n\rVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\"6\n\x10MessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"v\n\x0e\x45ncryptMessage\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64isplay_only\x18\x03 \x01(\x08\x12\x11\n\taddress_n\x18\x04 \x03(\r\x12\x1a\n\tcoin_name\x18\x05 \x01(\t:\x07\x42itcoin\"@\n\x10\x45ncryptedMessage\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0c\n\x04hmac\x18\x03 \x01(\x0c\"Q\n\x0e\x44\x65\x63ryptMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x0c\n\x04hmac\x18\x04 \x01(\x0c\"4\n\x10\x44\x65\x63ryptedMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"\x8c\x01\n\x0e\x43ipherKeyValue\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\x0c\x12\x0f\n\x07\x65ncrypt\x18\x04 \x01(\x08\x12\x16\n\x0e\x61sk_on_encrypt\x18\x05 \x01(\x08\x12\x16\n\x0e\x61sk_on_decrypt\x18\x06 \x01(\x08\x12\n\n\x02iv\x18\x07 \x01(\x0c\"!\n\x10\x43ipheredKeyValue\x12\r\n\x05value\x18\x01 \x01(\x0c\"\xce\x01\n\x06SignTx\x12\x15\n\routputs_count\x18\x01 \x02(\r\x12\x14\n\x0cinputs_count\x18\x02 \x02(\r\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x12\n\x07version\x18\x04 \x01(\r:\x01\x31\x12\x14\n\tlock_time\x18\x05 \x01(\r:\x01\x30\x12\x0e\n\x06\x65xpiry\x18\x06 \x01(\r\x12\x14\n\x0coverwintered\x18\x07 \x01(\x08\x12\x18\n\x10version_group_id\x18\x08 \x01(\r\x12\x11\n\tbranch_id\x18\n \x01(\r\"\x85\x01\n\tTxRequest\x12\"\n\x0crequest_type\x18\x01 \x01(\x0e\x32\x0c.RequestType\x12&\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x15.TxRequestDetailsType\x12,\n\nserialized\x18\x03 \x01(\x0b\x32\x18.TxRequestSerializedType\"%\n\x05TxAck\x12\x1c\n\x02tx\x18\x01 \x01(\x0b\x32\x10.TransactionType\"+\n\x08RawTxAck\x12\x1f\n\x02tx\x18\x01 \x01(\x0b\x32\x13.RawTransactionType\"}\n\x0cSignIdentity\x12\x1f\n\x08identity\x18\x01 \x01(\x0b\x32\r.IdentityType\x12\x18\n\x10\x63hallenge_hidden\x18\x02 \x01(\x0c\x12\x18\n\x10\x63hallenge_visual\x18\x03 \x01(\t\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x04 \x01(\t\"H\n\x0eSignedIdentity\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x12\n\npublic_key\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\",\n\rApplyPolicies\x12\x1b\n\x06policy\x18\x01 \x03(\x0b\x32\x0b.PolicyType\"?\n\tFlashHash\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\x12\x11\n\tchallenge\x18\x03 \x01(\x0c\":\n\nFlashWrite\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rase\x18\x03 \x01(\x08\"!\n\x11\x46lashHashResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"5\n\x12\x44\x65\x62ugLinkFlashDump\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\"*\n\x1a\x44\x65\x62ugLinkFlashDumpResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x0b\n\tSoftReset\"\x0f\n\rFirmwareErase\"7\n\x0e\x46irmwareUpload\x12\x14\n\x0cpayload_hash\x18\x01 \x02(\x0c\x12\x0f\n\x07payload\x18\x02 \x02(\x0c\"#\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\xd7\x02\n\x0e\x44\x65\x62ugLinkState\x12\x0e\n\x06layout\x18\x01 \x01(\x0c\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x0e\n\x06matrix\x18\x03 \x01(\t\x12\x10\n\x08mnemonic\x18\x04 \x01(\t\x12\x19\n\x04node\x18\x05 \x01(\x0b\x32\x0b.HDNodeType\x12\x1d\n\x15passphrase_protection\x18\x06 \x01(\x08\x12\x12\n\nreset_word\x18\x07 \x01(\t\x12\x15\n\rreset_entropy\x18\x08 \x01(\x0c\x12\x1a\n\x12recovery_fake_word\x18\t \x01(\t\x12\x19\n\x11recovery_word_pos\x18\n \x01(\r\x12\x17\n\x0frecovery_cipher\x18\x0b \x01(\t\x12$\n\x1crecovery_auto_completed_word\x18\x0c \x01(\t\x12\x15\n\rfirmware_hash\x18\r \x01(\x0c\x12\x14\n\x0cstorage_hash\x18\x0e \x01(\x0c\"\x0f\n\rDebugLinkStop\";\n\x0c\x44\x65\x62ugLinkLog\x12\r\n\x05level\x18\x01 \x01(\r\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\"\x15\n\x13\x44\x65\x62ugLinkFillConfig\" \n\x0e\x43hangeWipeCode\x12\x0e\n\x06remove\x18\x01 \x01(\x08*\xc5.\n\x0bMessageType\x12 \n\x16MessageType_Initialize\x10\x00\x1a\x04\x90\xb5\x18\x01\x12\x1a\n\x10MessageType_Ping\x10\x01\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Success\x10\x02\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_Failure\x10\x03\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ChangePin\x10\x04\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_WipeDevice\x10\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_FirmwareErase\x10\x06\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_FirmwareUpload\x10\x07\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetEntropy\x10\t\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Entropy\x10\n\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_GetPublicKey\x10\x0b\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_PublicKey\x10\x0c\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_LoadDevice\x10\r\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_ResetDevice\x10\x0e\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_SignTx\x10\x0f\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_Features\x10\x11\x1a\x04\x98\xb5\x18\x01\x12&\n\x1cMessageType_PinMatrixRequest\x10\x12\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_PinMatrixAck\x10\x13\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_Cancel\x10\x14\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_TxRequest\x10\x15\x1a\x04\x98\xb5\x18\x01\x12\x1b\n\x11MessageType_TxAck\x10\x16\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_CipherKeyValue\x10\x17\x1a\x04\x90\xb5\x18\x01\x12\"\n\x18MessageType_ClearSession\x10\x18\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplySettings\x10\x19\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ButtonRequest\x10\x1a\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ButtonAck\x10\x1b\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetAddress\x10\x1d\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Address\x10\x1e\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EntropyRequest\x10#\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_EntropyAck\x10$\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_SignMessage\x10&\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_VerifyMessage\x10\'\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_MessageSignature\x10(\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1dMessageType_PassphraseRequest\x10)\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_PassphraseAck\x10*\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_RecoveryDevice\x10-\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_WordRequest\x10.\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_WordAck\x10/\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CipheredKeyValue\x10\x30\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EncryptMessage\x10\x31\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_EncryptedMessage\x10\x32\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_DecryptMessage\x10\x33\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_DecryptedMessage\x10\x34\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_SignIdentity\x10\x35\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_SignedIdentity\x10\x36\x1a\x04\x98\xb5\x18\x01\x12!\n\x17MessageType_GetFeatures\x10\x37\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumGetAddress\x10\x38\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_EthereumAddress\x10\x39\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumSignTx\x10:\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_EthereumTxRequest\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\x10<\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CharacterRequest\x10P\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_CharacterAck\x10Q\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_RawTxAck\x10R\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplyPolicies\x10S\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_FlashHash\x10T\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_FlashWrite\x10U\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_FlashHashResponse\x10V\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_DebugLinkFlashDump\x10W\x1a\x04\xa0\xb5\x18\x01\x12\x30\n&MessageType_DebugLinkFlashDumpResponse\x10X\x1a\x04\xa8\xb5\x18\x01\x12\x1f\n\x15MessageType_SoftReset\x10Y\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkDecision\x10\x64\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkGetState\x10\x65\x1a\x04\xa0\xb5\x18\x01\x12$\n\x1aMessageType_DebugLinkState\x10\x66\x1a\x04\xa8\xb5\x18\x01\x12#\n\x19MessageType_DebugLinkStop\x10g\x1a\x04\xa0\xb5\x18\x01\x12\"\n\x18MessageType_DebugLinkLog\x10h\x1a\x04\xa8\xb5\x18\x01\x12)\n\x1fMessageType_DebugLinkFillConfig\x10i\x1a\x04\xa8\xb5\x18\x01\x12\"\n\x18MessageType_GetCoinTable\x10j\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_CoinTable\x10k\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_EthereumSignMessage\x10l\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumVerifyMessage\x10m\x1a\x04\x90\xb5\x18\x01\x12.\n$MessageType_EthereumMessageSignature\x10n\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_ChangeWipeCode\x10o\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumSignTypedHash\x10p\x1a\x04\x90\xb5\x18\x01\x12\x30\n&MessageType_EthereumTypedDataSignature\x10q\x1a\x04\x98\xb5\x18\x01\x12,\n\"MessageType_Ethereum712TypesValues\x10r\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_RippleGetAddress\x10\x90\x03\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_RippleAddress\x10\x91\x03\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_RippleSignTx\x10\x92\x03\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_RippleSignedTx\x10\x93\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainGetAddress\x10\xf4\x03\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_ThorchainAddress\x10\xf5\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainSignTx\x10\xf6\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainMsgRequest\x10\xf7\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainMsgAck\x10\xf8\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_ThorchainSignedTx\x10\xf9\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_EosGetPublicKey\x10\xd8\x04\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_EosPublicKey\x10\xd9\x04\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_EosSignTx\x10\xda\x04\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_EosTxActionRequest\x10\xdb\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_EosTxActionAck\x10\xdc\x04\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_EosSignedTx\x10\xdd\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NanoGetAddress\x10\xbc\x05\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NanoAddress\x10\xbd\x05\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NanoSignTx\x10\xbe\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NanoSignedTx\x10\xbf\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_BinanceGetAddress\x10\xa0\x06\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_BinanceAddress\x10\xa1\x06\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_BinanceGetPublicKey\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinancePublicKey\x10\xa3\x06\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_BinanceSignTx\x10\xa4\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceTxRequest\x10\xa5\x06\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_BinanceTransferMsg\x10\xa6\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceOrderMsg\x10\xa7\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceCancelMsg\x10\xa8\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceSignedTx\x10\xa9\x06\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosGetAddress\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_CosmosAddress\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosSignTx\x10\x86\x07\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRequest\x10\x87\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosMsgAck\x10\x88\x07\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_CosmosSignedTx\x10\x89\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_CosmosMsgDelegate\x10\x8a\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgUndelegate\x10\x8b\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgRedelegate\x10\x8c\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRewards\x10\x8d\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_CosmosMsgIBCTransfer\x10\x8e\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintGetAddress\x10\xe8\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintAddress\x10\xe9\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintSignTx\x10\xea\x07\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TendermintMsgRequest\x10\xeb\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintMsgAck\x10\xec\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintMsgSend\x10\xed\x07\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_TendermintSignedTx\x10\xee\x07\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_TendermintMsgDelegate\x10\xef\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgUndelegate\x10\xf0\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgRedelegate\x10\xf1\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintMsgRewards\x10\xf2\x07\x1a\x04\x98\xb5\x18\x01\x12/\n$MessageType_TendermintMsgIBCTransfer\x10\xf3\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisGetAddress\x10\xcc\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisAddress\x10\xcd\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisSignTx\x10\xce\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRequest\x10\xcf\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisMsgAck\x10\xd0\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSend\x10\xd1\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgDelegate\x10\xd2\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgUndelegate\x10\xd3\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgRedelegate\x10\xd4\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRewards\x10\xd5\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisMsgLPAdd\x10\xd6\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgLPRemove\x10\xd7\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgLPStake\x10\xd8\x08\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_OsmosisMsgLPUnstake\x10\xd9\x08\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_OsmosisMsgIBCTransfer\x10\xda\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSwap\x10\xdb\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisSignedTx\x10\xdc\x08\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_MayachainGetAddress\x10\xb0\t\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_MayachainAddress\x10\xb1\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainSignTx\x10\xb2\t\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_MayachainMsgRequest\x10\xb3\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainMsgAck\x10\xb4\t\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_MayachainSignedTx\x10\xb5\t\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') + serialized_pb=_b('\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xaa\x04\n\x08\x46\x65\x61tures\x12\x0e\n\x06vendor\x18\x01 \x01(\t\x12\x15\n\rmajor_version\x18\x02 \x01(\r\x12\x15\n\rminor_version\x18\x03 \x01(\r\x12\x15\n\rpatch_version\x18\x04 \x01(\r\x12\x17\n\x0f\x62ootloader_mode\x18\x05 \x01(\x08\x12\x11\n\tdevice_id\x18\x06 \x01(\t\x12\x16\n\x0epin_protection\x18\x07 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x08 \x01(\x08\x12\x10\n\x08language\x18\t \x01(\t\x12\r\n\x05label\x18\n \x01(\t\x12\x18\n\x05\x63oins\x18\x0b \x03(\x0b\x32\t.CoinType\x12\x13\n\x0binitialized\x18\x0c \x01(\x08\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x17\n\x0f\x62ootloader_hash\x18\x0e \x01(\x0c\x12\x10\n\x08imported\x18\x0f \x01(\x08\x12\x12\n\npin_cached\x18\x10 \x01(\x08\x12\x19\n\x11passphrase_cached\x18\x11 \x01(\x08\x12\x1d\n\x08policies\x18\x12 \x03(\x0b\x32\x0b.PolicyType\x12\r\n\x05model\x18\x15 \x01(\t\x12\x18\n\x10\x66irmware_variant\x18\x16 \x01(\t\x12\x15\n\rfirmware_hash\x18\x17 \x01(\x0c\x12\x11\n\tno_backup\x18\x18 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x19 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x1a \x01(\r\"*\n\x0cGetCoinTable\x12\r\n\x05start\x18\x01 \x01(\r\x12\x0b\n\x03\x65nd\x18\x02 \x01(\r\"L\n\tCoinTable\x12\x18\n\x05table\x18\x01 \x03(\x0b\x32\t.CoinType\x12\x11\n\tnum_coins\x18\x02 \x01(\r\x12\x12\n\nchunk_size\x18\x03 \x01(\r\"\x0e\n\x0c\x43learSession\"y\n\rApplySettings\x12\x10\n\x08language\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x16\n\x0euse_passphrase\x18\x03 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x04 \x01(\r\x12\x13\n\x0bu2f_counter\x18\x05 \x01(\r\"\x1b\n\tChangePin\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x87\x01\n\x04Ping\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x19\n\x11\x62utton_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x05 \x01(\x08\"\x1a\n\x07Success\x12\x0f\n\x07message\x18\x01 \x01(\t\"6\n\x07\x46\x61ilure\x12\x1a\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x0c.FailureType\x12\x0f\n\x07message\x18\x02 \x01(\t\"?\n\rButtonRequest\x12 \n\x04\x63ode\x18\x01 \x01(\x0e\x32\x12.ButtonRequestType\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x0b\n\tButtonAck\"7\n\x10PinMatrixRequest\x12#\n\x04type\x18\x01 \x01(\x0e\x32\x15.PinMatrixRequestType\"\x1b\n\x0cPinMatrixAck\x12\x0b\n\x03pin\x18\x01 \x02(\t\"\x08\n\x06\x43\x61ncel\"\x13\n\x11PassphraseRequest\"#\n\rPassphraseAck\x12\x12\n\npassphrase\x18\x01 \x02(\t\"\x1a\n\nGetEntropy\x12\x0c\n\x04size\x18\x01 \x02(\r\"\x1a\n\x07\x45ntropy\x12\x0f\n\x07\x65ntropy\x18\x01 \x02(\x0c\"\xa2\x01\n\x0cGetPublicKey\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x02 \x01(\t\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"4\n\tPublicKey\x12\x19\n\x04node\x18\x01 \x02(\x0b\x32\x0b.HDNodeType\x12\x0c\n\x04xpub\x18\x02 \x01(\t\"\xb3\x01\n\nGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1a\n\tcoin_name\x18\x02 \x01(\t:\x07\x42itcoin\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12+\n\x08multisig\x18\x04 \x01(\x0b\x32\x19.MultisigRedeemScriptType\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"\x1a\n\x07\x41\x64\x64ress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\t\"\x0c\n\nWipeDevice\"\xbb\x01\n\nLoadDevice\x12\x10\n\x08mnemonic\x18\x01 \x01(\t\x12\x19\n\x04node\x18\x02 \x01(\x0b\x32\x0b.HDNodeType\x12\x0b\n\x03pin\x18\x03 \x01(\t\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x15\n\rskip_checksum\x18\x07 \x01(\x08\x12\x13\n\x0bu2f_counter\x18\x08 \x01(\r\"\xe1\x01\n\x0bResetDevice\x12\x16\n\x0e\x64isplay_random\x18\x01 \x01(\x08\x12\x15\n\x08strength\x18\x02 \x01(\r:\x03\x32\x35\x36\x12\x1d\n\x15passphrase_protection\x18\x03 \x01(\x08\x12\x16\n\x0epin_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x11\n\tno_backup\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\"\x10\n\x0e\x45ntropyRequest\"\x1d\n\nEntropyAck\x12\x0f\n\x07\x65ntropy\x18\x01 \x01(\x0c\"\xff\x01\n\x0eRecoveryDevice\x12\x12\n\nword_count\x18\x01 \x01(\r\x12\x1d\n\x15passphrase_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x19\n\x08language\x18\x04 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x05 \x01(\t\x12\x18\n\x10\x65nforce_wordlist\x18\x06 \x01(\x08\x12\x1c\n\x14use_character_cipher\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x0f\n\x07\x64ry_run\x18\n \x01(\x08\"\r\n\x0bWordRequest\"\x17\n\x07WordAck\x12\x0c\n\x04word\x18\x01 \x02(\t\";\n\x10\x43haracterRequest\x12\x10\n\x08word_pos\x18\x01 \x02(\r\x12\x15\n\rcharacter_pos\x18\x02 \x02(\r\"?\n\x0c\x43haracterAck\x12\x11\n\tcharacter\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64one\x18\x03 \x01(\x08\"\x82\x01\n\x0bSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"`\n\rVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\"6\n\x10MessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"v\n\x0e\x45ncryptMessage\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64isplay_only\x18\x03 \x01(\x08\x12\x11\n\taddress_n\x18\x04 \x03(\r\x12\x1a\n\tcoin_name\x18\x05 \x01(\t:\x07\x42itcoin\"@\n\x10\x45ncryptedMessage\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0c\n\x04hmac\x18\x03 \x01(\x0c\"Q\n\x0e\x44\x65\x63ryptMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x0c\n\x04hmac\x18\x04 \x01(\x0c\"4\n\x10\x44\x65\x63ryptedMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"\x8c\x01\n\x0e\x43ipherKeyValue\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\x0c\x12\x0f\n\x07\x65ncrypt\x18\x04 \x01(\x08\x12\x16\n\x0e\x61sk_on_encrypt\x18\x05 \x01(\x08\x12\x16\n\x0e\x61sk_on_decrypt\x18\x06 \x01(\x08\x12\n\n\x02iv\x18\x07 \x01(\x0c\"!\n\x10\x43ipheredKeyValue\x12\r\n\x05value\x18\x01 \x01(\x0c\"\xce\x01\n\x06SignTx\x12\x15\n\routputs_count\x18\x01 \x02(\r\x12\x14\n\x0cinputs_count\x18\x02 \x02(\r\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x12\n\x07version\x18\x04 \x01(\r:\x01\x31\x12\x14\n\tlock_time\x18\x05 \x01(\r:\x01\x30\x12\x0e\n\x06\x65xpiry\x18\x06 \x01(\r\x12\x14\n\x0coverwintered\x18\x07 \x01(\x08\x12\x18\n\x10version_group_id\x18\x08 \x01(\r\x12\x11\n\tbranch_id\x18\n \x01(\r\"\x85\x01\n\tTxRequest\x12\"\n\x0crequest_type\x18\x01 \x01(\x0e\x32\x0c.RequestType\x12&\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x15.TxRequestDetailsType\x12,\n\nserialized\x18\x03 \x01(\x0b\x32\x18.TxRequestSerializedType\"%\n\x05TxAck\x12\x1c\n\x02tx\x18\x01 \x01(\x0b\x32\x10.TransactionType\"+\n\x08RawTxAck\x12\x1f\n\x02tx\x18\x01 \x01(\x0b\x32\x13.RawTransactionType\"}\n\x0cSignIdentity\x12\x1f\n\x08identity\x18\x01 \x01(\x0b\x32\r.IdentityType\x12\x18\n\x10\x63hallenge_hidden\x18\x02 \x01(\x0c\x12\x18\n\x10\x63hallenge_visual\x18\x03 \x01(\t\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x04 \x01(\t\"H\n\x0eSignedIdentity\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x12\n\npublic_key\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\",\n\rApplyPolicies\x12\x1b\n\x06policy\x18\x01 \x03(\x0b\x32\x0b.PolicyType\"?\n\tFlashHash\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\x12\x11\n\tchallenge\x18\x03 \x01(\x0c\":\n\nFlashWrite\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rase\x18\x03 \x01(\x08\"!\n\x11\x46lashHashResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"5\n\x12\x44\x65\x62ugLinkFlashDump\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\"*\n\x1a\x44\x65\x62ugLinkFlashDumpResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x0b\n\tSoftReset\"\x0f\n\rFirmwareErase\"7\n\x0e\x46irmwareUpload\x12\x14\n\x0cpayload_hash\x18\x01 \x02(\x0c\x12\x0f\n\x07payload\x18\x02 \x02(\x0c\"#\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\xd7\x02\n\x0e\x44\x65\x62ugLinkState\x12\x0e\n\x06layout\x18\x01 \x01(\x0c\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x0e\n\x06matrix\x18\x03 \x01(\t\x12\x10\n\x08mnemonic\x18\x04 \x01(\t\x12\x19\n\x04node\x18\x05 \x01(\x0b\x32\x0b.HDNodeType\x12\x1d\n\x15passphrase_protection\x18\x06 \x01(\x08\x12\x12\n\nreset_word\x18\x07 \x01(\t\x12\x15\n\rreset_entropy\x18\x08 \x01(\x0c\x12\x1a\n\x12recovery_fake_word\x18\t \x01(\t\x12\x19\n\x11recovery_word_pos\x18\n \x01(\r\x12\x17\n\x0frecovery_cipher\x18\x0b \x01(\t\x12$\n\x1crecovery_auto_completed_word\x18\x0c \x01(\t\x12\x15\n\rfirmware_hash\x18\r \x01(\x0c\x12\x14\n\x0cstorage_hash\x18\x0e \x01(\x0c\"\x0f\n\rDebugLinkStop\";\n\x0c\x44\x65\x62ugLinkLog\x12\r\n\x05level\x18\x01 \x01(\r\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\"\x15\n\x13\x44\x65\x62ugLinkFillConfig\" \n\x0e\x43hangeWipeCode\x12\x0e\n\x06remove\x18\x01 \x01(\x08*\xad\x32\n\x0bMessageType\x12 \n\x16MessageType_Initialize\x10\x00\x1a\x04\x90\xb5\x18\x01\x12\x1a\n\x10MessageType_Ping\x10\x01\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Success\x10\x02\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_Failure\x10\x03\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ChangePin\x10\x04\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_WipeDevice\x10\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_FirmwareErase\x10\x06\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_FirmwareUpload\x10\x07\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetEntropy\x10\t\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Entropy\x10\n\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_GetPublicKey\x10\x0b\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_PublicKey\x10\x0c\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_LoadDevice\x10\r\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_ResetDevice\x10\x0e\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_SignTx\x10\x0f\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_Features\x10\x11\x1a\x04\x98\xb5\x18\x01\x12&\n\x1cMessageType_PinMatrixRequest\x10\x12\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_PinMatrixAck\x10\x13\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_Cancel\x10\x14\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_TxRequest\x10\x15\x1a\x04\x98\xb5\x18\x01\x12\x1b\n\x11MessageType_TxAck\x10\x16\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_CipherKeyValue\x10\x17\x1a\x04\x90\xb5\x18\x01\x12\"\n\x18MessageType_ClearSession\x10\x18\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplySettings\x10\x19\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ButtonRequest\x10\x1a\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ButtonAck\x10\x1b\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetAddress\x10\x1d\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Address\x10\x1e\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EntropyRequest\x10#\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_EntropyAck\x10$\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_SignMessage\x10&\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_VerifyMessage\x10\'\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_MessageSignature\x10(\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1dMessageType_PassphraseRequest\x10)\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_PassphraseAck\x10*\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_RecoveryDevice\x10-\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_WordRequest\x10.\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_WordAck\x10/\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CipheredKeyValue\x10\x30\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EncryptMessage\x10\x31\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_EncryptedMessage\x10\x32\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_DecryptMessage\x10\x33\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_DecryptedMessage\x10\x34\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_SignIdentity\x10\x35\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_SignedIdentity\x10\x36\x1a\x04\x98\xb5\x18\x01\x12!\n\x17MessageType_GetFeatures\x10\x37\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumGetAddress\x10\x38\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_EthereumAddress\x10\x39\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumSignTx\x10:\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_EthereumTxRequest\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\x10<\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CharacterRequest\x10P\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_CharacterAck\x10Q\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_RawTxAck\x10R\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplyPolicies\x10S\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_FlashHash\x10T\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_FlashWrite\x10U\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_FlashHashResponse\x10V\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_DebugLinkFlashDump\x10W\x1a\x04\xa0\xb5\x18\x01\x12\x30\n&MessageType_DebugLinkFlashDumpResponse\x10X\x1a\x04\xa8\xb5\x18\x01\x12\x1f\n\x15MessageType_SoftReset\x10Y\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkDecision\x10\x64\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkGetState\x10\x65\x1a\x04\xa0\xb5\x18\x01\x12$\n\x1aMessageType_DebugLinkState\x10\x66\x1a\x04\xa8\xb5\x18\x01\x12#\n\x19MessageType_DebugLinkStop\x10g\x1a\x04\xa0\xb5\x18\x01\x12\"\n\x18MessageType_DebugLinkLog\x10h\x1a\x04\xa8\xb5\x18\x01\x12)\n\x1fMessageType_DebugLinkFillConfig\x10i\x1a\x04\xa8\xb5\x18\x01\x12\"\n\x18MessageType_GetCoinTable\x10j\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_CoinTable\x10k\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_EthereumSignMessage\x10l\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumVerifyMessage\x10m\x1a\x04\x90\xb5\x18\x01\x12.\n$MessageType_EthereumMessageSignature\x10n\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_ChangeWipeCode\x10o\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumSignTypedHash\x10p\x1a\x04\x90\xb5\x18\x01\x12\x30\n&MessageType_EthereumTypedDataSignature\x10q\x1a\x04\x98\xb5\x18\x01\x12,\n\"MessageType_Ethereum712TypesValues\x10r\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_RippleGetAddress\x10\x90\x03\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_RippleAddress\x10\x91\x03\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_RippleSignTx\x10\x92\x03\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_RippleSignedTx\x10\x93\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainGetAddress\x10\xf4\x03\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_ThorchainAddress\x10\xf5\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainSignTx\x10\xf6\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainMsgRequest\x10\xf7\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainMsgAck\x10\xf8\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_ThorchainSignedTx\x10\xf9\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_EosGetPublicKey\x10\xd8\x04\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_EosPublicKey\x10\xd9\x04\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_EosSignTx\x10\xda\x04\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_EosTxActionRequest\x10\xdb\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_EosTxActionAck\x10\xdc\x04\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_EosSignedTx\x10\xdd\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NanoGetAddress\x10\xbc\x05\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NanoAddress\x10\xbd\x05\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NanoSignTx\x10\xbe\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NanoSignedTx\x10\xbf\x05\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_SolanaGetAddress\x10\xee\x05\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_SolanaAddress\x10\xef\x05\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_SolanaSignTx\x10\xf0\x05\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_SolanaSignedTx\x10\xf1\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_SolanaSignMessage\x10\xf2\x05\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_SolanaMessageSignature\x10\xf3\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_BinanceGetAddress\x10\xa0\x06\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_BinanceAddress\x10\xa1\x06\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_BinanceGetPublicKey\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinancePublicKey\x10\xa3\x06\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_BinanceSignTx\x10\xa4\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceTxRequest\x10\xa5\x06\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_BinanceTransferMsg\x10\xa6\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceOrderMsg\x10\xa7\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceCancelMsg\x10\xa8\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceSignedTx\x10\xa9\x06\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosGetAddress\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_CosmosAddress\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosSignTx\x10\x86\x07\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRequest\x10\x87\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosMsgAck\x10\x88\x07\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_CosmosSignedTx\x10\x89\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_CosmosMsgDelegate\x10\x8a\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgUndelegate\x10\x8b\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgRedelegate\x10\x8c\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRewards\x10\x8d\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_CosmosMsgIBCTransfer\x10\x8e\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintGetAddress\x10\xe8\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintAddress\x10\xe9\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintSignTx\x10\xea\x07\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TendermintMsgRequest\x10\xeb\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintMsgAck\x10\xec\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintMsgSend\x10\xed\x07\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_TendermintSignedTx\x10\xee\x07\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_TendermintMsgDelegate\x10\xef\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgUndelegate\x10\xf0\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgRedelegate\x10\xf1\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintMsgRewards\x10\xf2\x07\x1a\x04\x98\xb5\x18\x01\x12/\n$MessageType_TendermintMsgIBCTransfer\x10\xf3\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisGetAddress\x10\xcc\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisAddress\x10\xcd\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisSignTx\x10\xce\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRequest\x10\xcf\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisMsgAck\x10\xd0\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSend\x10\xd1\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgDelegate\x10\xd2\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgUndelegate\x10\xd3\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgRedelegate\x10\xd4\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRewards\x10\xd5\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisMsgLPAdd\x10\xd6\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgLPRemove\x10\xd7\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgLPStake\x10\xd8\x08\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_OsmosisMsgLPUnstake\x10\xd9\x08\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_OsmosisMsgIBCTransfer\x10\xda\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSwap\x10\xdb\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisSignedTx\x10\xdc\x08\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_MayachainGetAddress\x10\xb0\t\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_MayachainAddress\x10\xb1\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainSignTx\x10\xb2\t\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_MayachainMsgRequest\x10\xb3\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainMsgAck\x10\xb4\t\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_MayachainSignedTx\x10\xb5\t\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_ZcashSignPCZT\x10\x94\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashPCZTAction\x10\x95\n\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_ZcashPCZTActionAck\x10\x96\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ZcashSignedPCZT\x10\x97\n\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_ZcashGetOrchardFVK\x10\x98\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashOrchardFVK\x10\x99\n\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') , dependencies=[types__pb2.DESCRIPTOR,]) @@ -416,234 +416,282 @@ options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceGetAddress', index=96, number=800, + name='MessageType_SolanaGetAddress', index=96, number=750, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceAddress', index=97, number=801, + name='MessageType_SolanaAddress', index=97, number=751, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceGetPublicKey', index=98, number=802, + name='MessageType_SolanaSignTx', index=98, number=752, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinancePublicKey', index=99, number=803, + name='MessageType_SolanaSignedTx', index=99, number=753, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceSignTx', index=100, number=804, + name='MessageType_SolanaSignMessage', index=100, number=754, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceTxRequest', index=101, number=805, + name='MessageType_SolanaMessageSignature', index=101, number=755, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceTransferMsg', index=102, number=806, + name='MessageType_BinanceGetAddress', index=102, number=800, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceOrderMsg', index=103, number=807, + name='MessageType_BinanceAddress', index=103, number=801, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceGetPublicKey', index=104, number=802, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinancePublicKey', index=105, number=803, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceSignTx', index=106, number=804, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceTxRequest', index=107, number=805, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceTransferMsg', index=108, number=806, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceOrderMsg', index=109, number=807, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceCancelMsg', index=104, number=808, + name='MessageType_BinanceCancelMsg', index=110, number=808, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_BinanceSignedTx', index=105, number=809, + name='MessageType_BinanceSignedTx', index=111, number=809, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosGetAddress', index=106, number=900, + name='MessageType_CosmosGetAddress', index=112, number=900, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosAddress', index=107, number=901, + name='MessageType_CosmosAddress', index=113, number=901, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosSignTx', index=108, number=902, + name='MessageType_CosmosSignTx', index=114, number=902, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgRequest', index=109, number=903, + name='MessageType_CosmosMsgRequest', index=115, number=903, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgAck', index=110, number=904, + name='MessageType_CosmosMsgAck', index=116, number=904, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosSignedTx', index=111, number=905, + name='MessageType_CosmosSignedTx', index=117, number=905, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgDelegate', index=112, number=906, + name='MessageType_CosmosMsgDelegate', index=118, number=906, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgUndelegate', index=113, number=907, + name='MessageType_CosmosMsgUndelegate', index=119, number=907, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgRedelegate', index=114, number=908, + name='MessageType_CosmosMsgRedelegate', index=120, number=908, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgRewards', index=115, number=909, + name='MessageType_CosmosMsgRewards', index=121, number=909, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_CosmosMsgIBCTransfer', index=116, number=910, + name='MessageType_CosmosMsgIBCTransfer', index=122, number=910, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintGetAddress', index=117, number=1000, + name='MessageType_TendermintGetAddress', index=123, number=1000, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintAddress', index=118, number=1001, + name='MessageType_TendermintAddress', index=124, number=1001, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintSignTx', index=119, number=1002, + name='MessageType_TendermintSignTx', index=125, number=1002, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgRequest', index=120, number=1003, + name='MessageType_TendermintMsgRequest', index=126, number=1003, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgAck', index=121, number=1004, + name='MessageType_TendermintMsgAck', index=127, number=1004, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgSend', index=122, number=1005, + name='MessageType_TendermintMsgSend', index=128, number=1005, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintSignedTx', index=123, number=1006, + name='MessageType_TendermintSignedTx', index=129, number=1006, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgDelegate', index=124, number=1007, + name='MessageType_TendermintMsgDelegate', index=130, number=1007, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgUndelegate', index=125, number=1008, + name='MessageType_TendermintMsgUndelegate', index=131, number=1008, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgRedelegate', index=126, number=1009, + name='MessageType_TendermintMsgRedelegate', index=132, number=1009, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgRewards', index=127, number=1010, + name='MessageType_TendermintMsgRewards', index=133, number=1010, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_TendermintMsgIBCTransfer', index=128, number=1011, + name='MessageType_TendermintMsgIBCTransfer', index=134, number=1011, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisGetAddress', index=129, number=1100, + name='MessageType_OsmosisGetAddress', index=135, number=1100, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisAddress', index=130, number=1101, + name='MessageType_OsmosisAddress', index=136, number=1101, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisSignTx', index=131, number=1102, + name='MessageType_OsmosisSignTx', index=137, number=1102, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgRequest', index=132, number=1103, + name='MessageType_OsmosisMsgRequest', index=138, number=1103, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgAck', index=133, number=1104, + name='MessageType_OsmosisMsgAck', index=139, number=1104, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgSend', index=134, number=1105, + name='MessageType_OsmosisMsgSend', index=140, number=1105, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgDelegate', index=135, number=1106, + name='MessageType_OsmosisMsgDelegate', index=141, number=1106, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgUndelegate', index=136, number=1107, + name='MessageType_OsmosisMsgUndelegate', index=142, number=1107, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgRedelegate', index=137, number=1108, + name='MessageType_OsmosisMsgRedelegate', index=143, number=1108, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgRewards', index=138, number=1109, + name='MessageType_OsmosisMsgRewards', index=144, number=1109, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgLPAdd', index=139, number=1110, + name='MessageType_OsmosisMsgLPAdd', index=145, number=1110, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgLPRemove', index=140, number=1111, + name='MessageType_OsmosisMsgLPRemove', index=146, number=1111, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgLPStake', index=141, number=1112, + name='MessageType_OsmosisMsgLPStake', index=147, number=1112, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgLPUnstake', index=142, number=1113, + name='MessageType_OsmosisMsgLPUnstake', index=148, number=1113, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgIBCTransfer', index=143, number=1114, + name='MessageType_OsmosisMsgIBCTransfer', index=149, number=1114, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisMsgSwap', index=144, number=1115, + name='MessageType_OsmosisMsgSwap', index=150, number=1115, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_OsmosisSignedTx', index=145, number=1116, + name='MessageType_OsmosisSignedTx', index=151, number=1116, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainGetAddress', index=146, number=1200, + name='MessageType_MayachainGetAddress', index=152, number=1200, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainAddress', index=147, number=1201, + name='MessageType_MayachainAddress', index=153, number=1201, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainSignTx', index=148, number=1202, + name='MessageType_MayachainSignTx', index=154, number=1202, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainMsgRequest', index=149, number=1203, + name='MessageType_MayachainMsgRequest', index=155, number=1203, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainMsgAck', index=156, number=1204, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainSignedTx', index=157, number=1205, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashSignPCZT', index=158, number=1300, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashPCZTAction', index=159, number=1301, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashPCZTActionAck', index=160, number=1302, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashSignedPCZT', index=161, number=1303, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainMsgAck', index=150, number=1204, + name='MessageType_ZcashGetOrchardFVK', index=162, number=1304, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), type=None), _descriptor.EnumValueDescriptor( - name='MessageType_MayachainSignedTx', index=151, number=1205, + name='MessageType_ZcashOrchardFVK', index=163, number=1305, options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), type=None), ], containing_type=None, options=None, serialized_start=5101, - serialized_end=11058, + serialized_end=11546, ) _sym_db.RegisterEnumDescriptor(_MESSAGETYPE) @@ -744,6 +792,12 @@ MessageType_NanoAddress = 701 MessageType_NanoSignTx = 702 MessageType_NanoSignedTx = 703 +MessageType_SolanaGetAddress = 750 +MessageType_SolanaAddress = 751 +MessageType_SolanaSignTx = 752 +MessageType_SolanaSignedTx = 753 +MessageType_SolanaSignMessage = 754 +MessageType_SolanaMessageSignature = 755 MessageType_BinanceGetAddress = 800 MessageType_BinanceAddress = 801 MessageType_BinanceGetPublicKey = 802 @@ -800,6 +854,12 @@ MessageType_MayachainMsgRequest = 1203 MessageType_MayachainMsgAck = 1204 MessageType_MayachainSignedTx = 1205 +MessageType_ZcashSignPCZT = 1300 +MessageType_ZcashPCZTAction = 1301 +MessageType_ZcashPCZTActionAck = 1302 +MessageType_ZcashSignedPCZT = 1303 +MessageType_ZcashGetOrchardFVK = 1304 +MessageType_ZcashOrchardFVK = 1305 @@ -4374,6 +4434,18 @@ _MESSAGETYPE.values_by_name["MessageType_NanoSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_NanoSignedTx"].has_options = True _MESSAGETYPE.values_by_name["MessageType_NanoSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"].has_options = True _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_BinanceAddress"].has_options = True @@ -4486,4 +4558,16 @@ _MESSAGETYPE.values_by_name["MessageType_MayachainMsgAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) _MESSAGETYPE.values_by_name["MessageType_MayachainSignedTx"].has_options = True _MESSAGETYPE.values_by_name["MessageType_MayachainSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashSignPCZT"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashSignPCZT"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashPCZTAction"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashPCZTAction"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashPCZTActionAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashPCZTActionAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashSignedPCZT"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashSignedPCZT"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashGetOrchardFVK"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashGetOrchardFVK"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashOrchardFVK"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashOrchardFVK"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) # @@protoc_insertion_point(module_scope) diff --git a/keepkeylib/messages_solana_pb2.py b/keepkeylib/messages_solana_pb2.py new file mode 100644 index 00000000..5c4f9742 --- /dev/null +++ b/keepkeylib/messages_solana_pb2.py @@ -0,0 +1,322 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: messages-solana.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='messages-solana.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n\x15messages-solana.proto\"V\n\x10SolanaGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\" \n\rSolanaAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\"L\n\x0cSolanaSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0e\n\x06raw_tx\x18\x03 \x01(\x0c\"#\n\x0eSolanaSignedTx\x12\x11\n\tsignature\x18\x01 \x01(\x0c\"n\n\x11SolanaSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x19\n\tcoin_name\x18\x02 \x01(\t:\x06Solana\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x1a\n\x0cshow_display\x18\x04 \x01(\x08:\x04true\"?\n\x16SolanaMessageSignature\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x42\x32\n\x1a\x63om.keepkey.deviceprotocolB\x14KeepKeyMessageSolana') +) + + + + +_SOLANAGETADDRESS = _descriptor.Descriptor( + name='SolanaGetAddress', + full_name='SolanaGetAddress', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='SolanaGetAddress.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='SolanaGetAddress.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Solana").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='SolanaGetAddress.show_display', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=25, + serialized_end=111, +) + + +_SOLANAADDRESS = _descriptor.Descriptor( + name='SolanaAddress', + full_name='SolanaAddress', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='SolanaAddress.address', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=113, + serialized_end=145, +) + + +_SOLANASIGNTX = _descriptor.Descriptor( + name='SolanaSignTx', + full_name='SolanaSignTx', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='SolanaSignTx.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='SolanaSignTx.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Solana").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='raw_tx', full_name='SolanaSignTx.raw_tx', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=147, + serialized_end=223, +) + + +_SOLANASIGNEDTX = _descriptor.Descriptor( + name='SolanaSignedTx', + full_name='SolanaSignedTx', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signature', full_name='SolanaSignedTx.signature', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=225, + serialized_end=260, +) + + +_SOLANASIGNMESSAGE = _descriptor.Descriptor( + name='SolanaSignMessage', + full_name='SolanaSignMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='SolanaSignMessage.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='coin_name', full_name='SolanaSignMessage.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Solana").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='message', full_name='SolanaSignMessage.message', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='SolanaSignMessage.show_display', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=True, default_value=True, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=262, + serialized_end=372, +) + + +_SOLANAMESSAGESIGNATURE = _descriptor.Descriptor( + name='SolanaMessageSignature', + full_name='SolanaMessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='public_key', full_name='SolanaMessageSignature.public_key', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='signature', full_name='SolanaMessageSignature.signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=374, + serialized_end=437, +) + +DESCRIPTOR.message_types_by_name['SolanaGetAddress'] = _SOLANAGETADDRESS +DESCRIPTOR.message_types_by_name['SolanaAddress'] = _SOLANAADDRESS +DESCRIPTOR.message_types_by_name['SolanaSignTx'] = _SOLANASIGNTX +DESCRIPTOR.message_types_by_name['SolanaSignedTx'] = _SOLANASIGNEDTX +DESCRIPTOR.message_types_by_name['SolanaSignMessage'] = _SOLANASIGNMESSAGE +DESCRIPTOR.message_types_by_name['SolanaMessageSignature'] = _SOLANAMESSAGESIGNATURE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +SolanaGetAddress = _reflection.GeneratedProtocolMessageType('SolanaGetAddress', (_message.Message,), dict( + DESCRIPTOR = _SOLANAGETADDRESS, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaGetAddress) + )) +_sym_db.RegisterMessage(SolanaGetAddress) + +SolanaAddress = _reflection.GeneratedProtocolMessageType('SolanaAddress', (_message.Message,), dict( + DESCRIPTOR = _SOLANAADDRESS, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaAddress) + )) +_sym_db.RegisterMessage(SolanaAddress) + +SolanaSignTx = _reflection.GeneratedProtocolMessageType('SolanaSignTx', (_message.Message,), dict( + DESCRIPTOR = _SOLANASIGNTX, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaSignTx) + )) +_sym_db.RegisterMessage(SolanaSignTx) + +SolanaSignedTx = _reflection.GeneratedProtocolMessageType('SolanaSignedTx', (_message.Message,), dict( + DESCRIPTOR = _SOLANASIGNEDTX, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaSignedTx) + )) +_sym_db.RegisterMessage(SolanaSignedTx) + +SolanaSignMessage = _reflection.GeneratedProtocolMessageType('SolanaSignMessage', (_message.Message,), dict( + DESCRIPTOR = _SOLANASIGNMESSAGE, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaSignMessage) + )) +_sym_db.RegisterMessage(SolanaSignMessage) + +SolanaMessageSignature = _reflection.GeneratedProtocolMessageType('SolanaMessageSignature', (_message.Message,), dict( + DESCRIPTOR = _SOLANAMESSAGESIGNATURE, + __module__ = 'messages_solana_pb2' + # @@protoc_insertion_point(class_scope:SolanaMessageSignature) + )) +_sym_db.RegisterMessage(SolanaMessageSignature) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\024KeepKeyMessageSolana')) +# @@protoc_insertion_point(module_scope) diff --git a/keepkeylib/messages_zcash_pb2.py b/keepkeylib/messages_zcash_pb2.py new file mode 100644 index 00000000..ca0de41d --- /dev/null +++ b/keepkeylib/messages_zcash_pb2.py @@ -0,0 +1,483 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: messages-zcash.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='messages-zcash.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n\x14messages-zcash.proto\"\xc0\x02\n\rZcashSignPCZT\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x11\n\tpczt_data\x18\x03 \x01(\x0c\x12\x11\n\tn_actions\x18\x04 \x01(\r\x12\x14\n\x0ctotal_amount\x18\x05 \x01(\x04\x12\x0b\n\x03\x66\x65\x65\x18\x06 \x01(\x04\x12\x11\n\tbranch_id\x18\x07 \x01(\r\x12\x15\n\rheader_digest\x18\x08 \x01(\x0c\x12\x1a\n\x12transparent_digest\x18\t \x01(\x0c\x12\x16\n\x0esapling_digest\x18\n \x01(\x0c\x12\x16\n\x0eorchard_digest\x18\x0b \x01(\x0c\x12\x15\n\rorchard_flags\x18\x0c \x01(\r\x12\x1d\n\x15orchard_value_balance\x18\r \x01(\x03\x12\x16\n\x0eorchard_anchor\x18\x0e \x01(\x0c\"\x81\x02\n\x0fZcashPCZTAction\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x61lpha\x18\x02 \x01(\x0c\x12\x0f\n\x07sighash\x18\x03 \x01(\x0c\x12\x0e\n\x06\x63v_net\x18\x04 \x01(\x0c\x12\r\n\x05value\x18\x05 \x01(\x04\x12\x10\n\x08is_spend\x18\x06 \x01(\x08\x12\x11\n\tnullifier\x18\x07 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x08 \x01(\x0c\x12\x0b\n\x03\x65pk\x18\t \x01(\x0c\x12\x13\n\x0b\x65nc_compact\x18\n \x01(\x0c\x12\x10\n\x08\x65nc_memo\x18\x0b \x01(\x0c\x12\x16\n\x0e\x65nc_noncompact\x18\x0c \x01(\x0c\x12\n\n\x02rk\x18\r \x01(\x0c\x12\x16\n\x0eout_ciphertext\x18\x0e \x01(\x0c\"(\n\x12ZcashPCZTActionAck\x12\x12\n\nnext_index\x18\x01 \x01(\r\"3\n\x0fZcashSignedPCZT\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"N\n\x12ZcashGetOrchardFVK\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\"7\n\x0fZcashOrchardFVK\x12\n\n\x02\x61k\x18\x01 \x01(\x0c\x12\n\n\x02nk\x18\x02 \x01(\x0c\x12\x0c\n\x04rivk\x18\x03 \x01(\x0c\x42\x31\n\x1a\x63om.keepkey.deviceprotocolB\x13KeepKeyMessageZcash') +) + + + + +_ZCASHSIGNPCZT = _descriptor.Descriptor( + name='ZcashSignPCZT', + full_name='ZcashSignPCZT', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='ZcashSignPCZT.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='account', full_name='ZcashSignPCZT.account', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='pczt_data', full_name='ZcashSignPCZT.pczt_data', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='n_actions', full_name='ZcashSignPCZT.n_actions', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='total_amount', full_name='ZcashSignPCZT.total_amount', index=4, + number=5, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='fee', full_name='ZcashSignPCZT.fee', index=5, + number=6, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='branch_id', full_name='ZcashSignPCZT.branch_id', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='header_digest', full_name='ZcashSignPCZT.header_digest', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='transparent_digest', full_name='ZcashSignPCZT.transparent_digest', index=8, + number=9, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='sapling_digest', full_name='ZcashSignPCZT.sapling_digest', index=9, + number=10, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='orchard_digest', full_name='ZcashSignPCZT.orchard_digest', index=10, + number=11, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='orchard_flags', full_name='ZcashSignPCZT.orchard_flags', index=11, + number=12, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='orchard_value_balance', full_name='ZcashSignPCZT.orchard_value_balance', index=12, + number=13, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='orchard_anchor', full_name='ZcashSignPCZT.orchard_anchor', index=13, + number=14, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=25, + serialized_end=345, +) + + +_ZCASHPCZTACTION = _descriptor.Descriptor( + name='ZcashPCZTAction', + full_name='ZcashPCZTAction', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='index', full_name='ZcashPCZTAction.index', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='alpha', full_name='ZcashPCZTAction.alpha', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='sighash', full_name='ZcashPCZTAction.sighash', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cv_net', full_name='ZcashPCZTAction.cv_net', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='ZcashPCZTAction.value', index=4, + number=5, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='is_spend', full_name='ZcashPCZTAction.is_spend', index=5, + number=6, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='nullifier', full_name='ZcashPCZTAction.nullifier', index=6, + number=7, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmx', full_name='ZcashPCZTAction.cmx', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='epk', full_name='ZcashPCZTAction.epk', index=8, + number=9, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='enc_compact', full_name='ZcashPCZTAction.enc_compact', index=9, + number=10, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='enc_memo', full_name='ZcashPCZTAction.enc_memo', index=10, + number=11, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='enc_noncompact', full_name='ZcashPCZTAction.enc_noncompact', index=11, + number=12, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rk', full_name='ZcashPCZTAction.rk', index=12, + number=13, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='out_ciphertext', full_name='ZcashPCZTAction.out_ciphertext', index=13, + number=14, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=348, + serialized_end=605, +) + + +_ZCASHPCZTACTIONACK = _descriptor.Descriptor( + name='ZcashPCZTActionAck', + full_name='ZcashPCZTActionAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='next_index', full_name='ZcashPCZTActionAck.next_index', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=607, + serialized_end=647, +) + + +_ZCASHSIGNEDPCZT = _descriptor.Descriptor( + name='ZcashSignedPCZT', + full_name='ZcashSignedPCZT', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signatures', full_name='ZcashSignedPCZT.signatures', index=0, + number=1, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='txid', full_name='ZcashSignedPCZT.txid', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=649, + serialized_end=700, +) + + +_ZCASHGETORCHARDFVK = _descriptor.Descriptor( + name='ZcashGetOrchardFVK', + full_name='ZcashGetOrchardFVK', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='ZcashGetOrchardFVK.address_n', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='account', full_name='ZcashGetOrchardFVK.account', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='show_display', full_name='ZcashGetOrchardFVK.show_display', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=702, + serialized_end=780, +) + + +_ZCASHORCHARDFVK = _descriptor.Descriptor( + name='ZcashOrchardFVK', + full_name='ZcashOrchardFVK', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ak', full_name='ZcashOrchardFVK.ak', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='nk', full_name='ZcashOrchardFVK.nk', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rivk', full_name='ZcashOrchardFVK.rivk', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=782, + serialized_end=837, +) + +DESCRIPTOR.message_types_by_name['ZcashSignPCZT'] = _ZCASHSIGNPCZT +DESCRIPTOR.message_types_by_name['ZcashPCZTAction'] = _ZCASHPCZTACTION +DESCRIPTOR.message_types_by_name['ZcashPCZTActionAck'] = _ZCASHPCZTACTIONACK +DESCRIPTOR.message_types_by_name['ZcashSignedPCZT'] = _ZCASHSIGNEDPCZT +DESCRIPTOR.message_types_by_name['ZcashGetOrchardFVK'] = _ZCASHGETORCHARDFVK +DESCRIPTOR.message_types_by_name['ZcashOrchardFVK'] = _ZCASHORCHARDFVK +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ZcashSignPCZT = _reflection.GeneratedProtocolMessageType('ZcashSignPCZT', (_message.Message,), dict( + DESCRIPTOR = _ZCASHSIGNPCZT, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashSignPCZT) + )) +_sym_db.RegisterMessage(ZcashSignPCZT) + +ZcashPCZTAction = _reflection.GeneratedProtocolMessageType('ZcashPCZTAction', (_message.Message,), dict( + DESCRIPTOR = _ZCASHPCZTACTION, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashPCZTAction) + )) +_sym_db.RegisterMessage(ZcashPCZTAction) + +ZcashPCZTActionAck = _reflection.GeneratedProtocolMessageType('ZcashPCZTActionAck', (_message.Message,), dict( + DESCRIPTOR = _ZCASHPCZTACTIONACK, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashPCZTActionAck) + )) +_sym_db.RegisterMessage(ZcashPCZTActionAck) + +ZcashSignedPCZT = _reflection.GeneratedProtocolMessageType('ZcashSignedPCZT', (_message.Message,), dict( + DESCRIPTOR = _ZCASHSIGNEDPCZT, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashSignedPCZT) + )) +_sym_db.RegisterMessage(ZcashSignedPCZT) + +ZcashGetOrchardFVK = _reflection.GeneratedProtocolMessageType('ZcashGetOrchardFVK', (_message.Message,), dict( + DESCRIPTOR = _ZCASHGETORCHARDFVK, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashGetOrchardFVK) + )) +_sym_db.RegisterMessage(ZcashGetOrchardFVK) + +ZcashOrchardFVK = _reflection.GeneratedProtocolMessageType('ZcashOrchardFVK', (_message.Message,), dict( + DESCRIPTOR = _ZCASHORCHARDFVK, + __module__ = 'messages_zcash_pb2' + # @@protoc_insertion_point(class_scope:ZcashOrchardFVK) + )) +_sym_db.RegisterMessage(ZcashOrchardFVK) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\023KeepKeyMessageZcash')) +# @@protoc_insertion_point(module_scope) diff --git a/tests/test_nu6_final.py b/tests/test_nu6_final.py new file mode 100644 index 00000000..c7c870eb --- /dev/null +++ b/tests/test_nu6_final.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +""" +Final test: Sign and automatically broadcast NU6 transaction +""" + +import sys +import os + +# Add python-keepkey to path +sys.path.insert(0, 'deps/python-keepkey') +sys.path.insert(0, 'deps/python-keepkey/tests') + +from keepkeylib.client import KeepKeyClient +from keepkeylib import messages_pb2 as proto +from keepkeylib import types_pb2 +import config +import binascii +import requests +import json + +# Zcash RPC +RPC_USER = "zcashrpc" +RPC_PASSWORD = "your_password_here" +RPC_HOST = "100.117.181.111" +RPC_PORT = 8232 + +def rpc_call(method, params=[]): + url = f"http://{RPC_HOST}:{RPC_PORT}/" + headers = {'content-type': 'application/json'} + payload = { + "jsonrpc": "2.0", + "id": "test", + "method": method, + "params": params + } + response = requests.post(url, auth=(RPC_USER, RPC_PASSWORD), + headers=headers, data=json.dumps(payload)) + return response.json() + +def main(): + print("=" * 70) + print("NU6 FIRMWARE TEST - AUTOMATIC BROADCAST") + print("=" * 70) + + # Get device using config (same as working test) + transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) + client = KeepKeyClient(transport) + + # Get address + address = client.get_address("Zcash", [0x80000000 | 133, 0x80000000, 0x80000000, 0, 0]) + print(f"\n✓ Address: {address}") + + # Get blockchain info + info = rpc_call("getblockchaininfo") + height = info['result']['blocks'] + expiry_height = height + 40 + print(f"✓ Height: {height}, Expiry: {expiry_height}") + + # Find UTXO + utxos = rpc_call("listunspent", [0, 9999999, [address]]) + if not utxos['result']: + print("❌ No UTXOs found") + return False + + utxo = utxos['result'][0] + print(f"✓ Using UTXO: {utxo['txid']}:{utxo['vout']}") + print(f" Amount: {utxo['amount']} ZEC") + + # Get scriptPubKey + tx = rpc_call("getrawtransaction", [utxo['txid'], 1]) + output = tx['result']['vout'][utxo['vout']] + scriptpubkey_hex = output['scriptPubKey']['hex'] + scriptpubkey_bytes = binascii.unhexlify(scriptpubkey_hex) + + print(f" ScriptPubKey: {scriptpubkey_hex}") + + # Create input + amount = int(utxo['amount'] * 100000000) + inp = proto.TxInputType( + address_n=[0x80000000 | 133, 0x80000000, 0x80000000, 0, 0], + prev_hash=binascii.unhexlify(utxo['txid'])[::-1], + prev_index=utxo['vout'], + amount=amount, + script_type=types_pb2.SPENDADDRESS, + sequence=0xffffffff, + script_pubkey=scriptpubkey_bytes # Critical for NU6! + ) + + # Create outputs + out_amount = 45000 + fee = 10000 + change = amount - out_amount - fee + + out1 = proto.TxOutputType( + address="t1d3URKgTufDFhEr8pxm388kVjw1V4Ba1Ez", + amount=out_amount, + script_type=types_pb2.PAYTOADDRESS + ) + + out2 = proto.TxOutputType( + address=address, + amount=change, + script_type=types_pb2.PAYTOADDRESS + ) + + print(f"\n✓ Outputs:") + print(f" 1: {out_amount} sats") + print(f" 2: {change} sats (change)") + print(f" Fee: {fee} sats") + + # Sign transaction + print(f"\n✓ Signing...") + signed = client.sign_tx("Zcash", [inp], [out1, out2], version=5, + version_group_id=0x26A7270A, + branch_id=0xC8E71055, + lock_time=0, + expiry=expiry_height) + + tx_hex = binascii.hexlify(signed[1]).decode() + print(f"✓ Signed! ({len(tx_hex)//2} bytes)") + + # Write to file + with open('signed_tx.hex', 'w') as f: + f.write(tx_hex) + print(f"✓ Written to signed_tx.hex") + + # Broadcast + print(f"\n✓ Broadcasting...") + try: + result = rpc_call("sendrawtransaction", [tx_hex]) + if 'result' in result: + txid = result['result'] + print(f"\n🎉 SUCCESS! Transaction broadcast!") + print(f" TXID: {txid}") + print(f"\n✅ MONEY SENT SUCCESSFULLY FROM KEEPKEY FIRMWARE!") + return True + else: + print(f"\n❌ FAILED: {result.get('error', 'Unknown error')}") + # Try to get more details + test_result = rpc_call("testmempoolaccept", [[tx_hex]]) + if 'result' in test_result: + print(f" Test result: {test_result['result']}") + return False + except Exception as e: + print(f"❌ Error broadcasting: {e}") + return False + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/test_zcash_complete_nownodes.py b/tests/test_zcash_complete_nownodes.py new file mode 100755 index 00000000..b8f00de2 --- /dev/null +++ b/tests/test_zcash_complete_nownodes.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +""" +Complete Zcash v5 (NU6) transaction test with NOWNodes API +Tests the full workflow: +1. Generate xpub from device +2. Derive addresses from xpub +3. Find UTXOs using NOWNodes API +4. Fetch UTXO details (scriptPubKey) from blockchain +5. Sign transaction with firmware +6. Broadcast signed transaction to network +""" +import sys +import os +import binascii +import requests +from hashlib import sha256 +import hashlib + +# Setup paths +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'deps/python-keepkey')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'deps/python-keepkey/tests')) + +import config +from keepkeylib.client import KeepKeyClient, KeepKeyDebuglinkClient +import keepkeylib.messages_pb2 as proto +import keepkeylib.types_pb2 as proto_types +from keepkeylib import tx_api + +tx_api.cache_dir = 'txcache' + +# NOWNodes API configuration +NOWNODES_API_KEY = os.getenv('NOWNODES_API_KEY', '') # User needs to provide this +NOWNODES_BASE_URL = "https://zec.nownodes.io" + +# Zcash node configuration (fallback to local/remote node) +RPC_URL = os.getenv('ZCASH_RPC_URL', 'http://100.117.181.111:8232') +RPC_USER = os.getenv('ZCASH_RPC_USER', 'zcash') +RPC_PASS = os.getenv('ZCASH_RPC_PASS', '78787ba819a382122e2b4fd98e68db3419ba7cf11c3f22f3bcd07e5ac606e630') + +def rpc_call(method, params=[]): + """Make RPC call to zcashd node""" + payload = { + "jsonrpc": "1.0", + "id": "python", + "method": method, + "params": params + } + response = requests.post( + RPC_URL, + json=payload, + auth=(RPC_USER, RPC_PASS), + timeout=30 + ) + result = response.json() + + if result.get("error"): + raise Exception(f"RPC error: {result['error']}") + + return result["result"] + +def nownodes_call(method, params=[]): + """Make RPC call via NOWNodes API""" + if not NOWNODES_API_KEY: + print(" ⚠️ NOWNodes API key not set, falling back to local node") + return rpc_call(method, params) + + headers = { + 'Content-Type': 'application/json', + 'api-key': NOWNODES_API_KEY + } + + payload = { + "jsonrpc": "2.0", + "id": "python", + "method": method, + "params": params + } + + response = requests.post( + NOWNODES_BASE_URL, + json=payload, + headers=headers, + timeout=30 + ) + result = response.json() + + if result.get("error"): + raise Exception(f"NOWNodes error: {result['error']}") + + return result["result"] + +def get_xpub(client, path): + """Get extended public key from device""" + print(f" Getting xpub for path m/{'/'.join(map(str, path))}...") + + # Get public node + node = client.get_public_node(path, coin_name='Zcash') + + xpub = node.xpub + print(f" xpub: {xpub}") + + return xpub + +def derive_address_from_xpub(xpub, change, index): + """ + Derive P2PKH address from xpub (Zcash doesn't use segwit) + This is a simplified version - in production use a proper BIP32 library + """ + # This is a placeholder - would need full BIP32 implementation + # For now, we'll derive addresses directly from the device + return None + +def find_utxos_for_address(address): + """Find UTXOs for an address using blockchain API""" + print(f" Searching for UTXOs at {address}...") + + try: + # Try NOWNodes first - note: listunspent params are minconf, maxconf, [addresses] + utxos = nownodes_call("listunspent", [0, 9999999, [address]]) + print(f" ✓ Found {len(utxos)} UTXO(s) via NOWNodes") + return utxos + except Exception as e: + print(f" ⚠️ NOWNodes lookup failed: {e}") + + # For local RPC, we might need to import the address first + # or use scantxoutset instead + print(f" Trying scantxoutset...") + try: + # Use scantxoutset which doesn't require the address to be in the wallet + result = rpc_call("scantxoutset", ["start", [f"addr({address})"]]) + if result and 'unspents' in result: + utxos = [] + for unspent in result['unspents']: + utxos.append({ + 'txid': unspent['txid'], + 'vout': unspent['vout'], + 'amount': unspent['amount'], + 'scriptPubKey': unspent['scriptPubKey'] + }) + print(f" ✓ Found {len(utxos)} UTXO(s) via scantxoutset") + return utxos + except Exception as e2: + print(f" ⚠️ scantxoutset also failed: {e2}") + return [] + +def get_utxo_details(txid, vout): + """Get UTXO details including scriptPubKey from blockchain""" + print(f" Fetching UTXO: {txid}:{vout}", flush=True) + + try: + # Try NOWNodes first (verbose=1 for JSON output) + tx = nownodes_call("getrawtransaction", [txid, 1]) + except Exception as e: + print(f" ⚠️ NOWNodes failed: {e}") + print(f" Trying direct RPC...") + tx = rpc_call("getrawtransaction", [txid, 1]) + + # Get the specific output + if vout >= len(tx['vout']): + raise Exception(f"Output {vout} not found in transaction") + + output = tx['vout'][vout] + + # Extract scriptPubKey hex + scriptpubkey_hex = output['scriptPubKey']['hex'] + scriptpubkey_bytes = binascii.unhexlify(scriptpubkey_hex) + + # Get amount (in satoshis) + amount = int(output['value'] * 100000000) + + print(f" Amount: {amount} satoshis ({output['value']} ZEC)") + print(f" scriptPubKey: {scriptpubkey_hex}") + + return { + 'amount': amount, + 'scriptpubkey': scriptpubkey_bytes, + 'scriptpubkey_hex': scriptpubkey_hex, + 'address': output['scriptPubKey'].get('addresses', ['unknown'])[0] + } + +def test_complete_workflow(): + """Test complete Zcash workflow: xpub -> address -> UTXO -> sign -> broadcast""" + + print("=" * 70) + print("ZCASH COMPLETE WORKFLOW TEST (with NOWNodes)") + print("=" * 70) + + # Step 1: Connect to emulator + print("\nStep 1: Connecting to KeepKey emulator...") + + transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) + + if hasattr(config, 'DEBUG_TRANSPORT'): + debug_transport = config.DEBUG_TRANSPORT(*config.DEBUG_TRANSPORT_ARGS, **config.DEBUG_TRANSPORT_KWARGS) + client = KeepKeyDebuglinkClient(transport) + client.set_debuglink(debug_transport) + else: + client = KeepKeyClient(transport) + + client.set_tx_api(tx_api.TxApiBitcoin) + print(" ✓ Connected") + + # Step 2: Initialize device + print("\nStep 2: Initializing device...") + client.wipe_device() + client.load_device_by_mnemonic( + mnemonic='all all all all all all all all all all all all', + pin='', + passphrase_protection=False, + label='ZcashTest', + language='english' + ) + print(" ✓ Device initialized") + + # Step 3: Generate xpub (BIP44 path for Zcash: m/44'/133'/0') + print("\nStep 3: Generating xpub...") + ACCOUNT_PATH = [44 | 0x80000000, 133 | 0x80000000, 0 | 0x80000000] # m/44'/133'/0' + + try: + xpub = get_xpub(client, ACCOUNT_PATH) + print(f" ✓ xpub generated successfully") + except Exception as e: + print(f" ⚠️ Could not generate xpub: {e}") + xpub = None + + # Step 4: Derive address (using simple path that matches our test UTXO) + print("\nStep 4: Deriving receive address...") + SOURCE_PATH = [0, 0] # Simple m/0/0 path for testing + address = client.get_address('Zcash', SOURCE_PATH) + print(f" Address: {address}") + print(f" Path: m/0/0 (test path)") + + # Step 5: Find UTXOs using NOWNodes/RPC + print("\nStep 5: Finding UTXOs...") + utxos = find_utxos_for_address(address) + + if not utxos: + print(f" ❌ No UTXOs found for {address}") + print(f" Please send ZEC to this address first") + + # Check if there's a known UTXO we can use + known_txid = "d4c5e482c35235510767f6bd173e453f672975dc7e67d67a00dd5a999837a6a6" + known_vout = 1 + + print(f"\n Checking known UTXO: {known_txid}:{known_vout}") + try: + utxo_details = get_utxo_details(known_txid, known_vout) + + # Create synthetic UTXO entry + utxos = [{ + 'txid': known_txid, + 'vout': known_vout, + 'amount': utxo_details['amount'] / 100000000, + 'scriptPubKey': utxo_details['scriptpubkey_hex'] + }] + print(f" ✓ Using known UTXO") + except Exception as e: + print(f" ❌ Could not fetch known UTXO: {e}") + return False + + # Use first UTXO + utxo = utxos[0] + print(f" ✓ Found {len(utxos)} UTXO(s), using first one") + print(f" TXID: {utxo['txid']}") + print(f" VOUT: {utxo['vout']}") + print(f" Amount: {utxo['amount']} ZEC") + + # Step 6: Get blockchain info for expiry + print("\nStep 6: Getting blockchain info...") + try: + blockchain_info = nownodes_call("getblockchaininfo") + except: + blockchain_info = rpc_call("getblockchaininfo") + + current_height = blockchain_info['blocks'] + expiry_height = current_height + 40 + print(f" Current height: {current_height}") + print(f" Expiry height: {expiry_height}") + + # Step 7: Fetch UTXO details + print("\nStep 7: Fetching UTXO details...") + utxo_details = get_utxo_details(utxo['txid'], utxo['vout']) + + # Step 8: Create transaction inputs with scriptPubKey + print("\nStep 8: Creating transaction inputs...") + + UTXO_TXID = utxo['txid'] + UTXO_VOUT = utxo['vout'] + UTXO_AMOUNT = utxo_details['amount'] + UTXO_SCRIPTPUBKEY = utxo_details['scriptpubkey'] + + inp1 = proto_types.TxInputType( + address_n=SOURCE_PATH, + prev_hash=binascii.unhexlify(UTXO_TXID), + prev_index=UTXO_VOUT, + amount=UTXO_AMOUNT, + script_pubkey=UTXO_SCRIPTPUBKEY # Critical for ZIP-244! + ) + + print(f" ✓ Input created with scriptPubKey: {utxo_details['scriptpubkey_hex']}") + + # Step 9: Create transaction outputs + print("\nStep 9: Creating transaction outputs...") + + SEND_AMOUNT = 10000 # 0.0001 ZEC + FEE = 10000 # 0.0001 ZEC + CHANGE_AMOUNT = UTXO_AMOUNT - SEND_AMOUNT - FEE + + DEST_ADDRESS = "t1d3URKgTufDFhEr8pxm388kVjw1V4Ba1Ez" + + out1 = proto_types.TxOutputType( + address=DEST_ADDRESS, + amount=SEND_AMOUNT, + script_type=proto_types.PAYTOADDRESS, + ) + + out2 = proto_types.TxOutputType( + address=address, + amount=CHANGE_AMOUNT, + script_type=proto_types.PAYTOADDRESS, + ) + + print(f" Output 1: {SEND_AMOUNT/100000000} ZEC to {DEST_ADDRESS}") + print(f" Output 2: {CHANGE_AMOUNT/100000000} ZEC (change) to {address}") + print(f" Fee: {FEE/100000000} ZEC") + + # Step 10: Sign transaction + print("\nStep 10: Signing transaction (version 5)...") + + try: + (signatures, serialized_tx) = client.sign_tx( + 'Zcash', + [inp1], + [out1, out2], + version=5, + lock_time=0, + expiry=expiry_height + ) + + tx_hex = binascii.hexlify(serialized_tx).decode('ascii') + print(f" ✓ Transaction signed successfully!") + print(f" Transaction length: {len(serialized_tx)} bytes") + print(f" TX hex (first 100 chars): {tx_hex[:100]}...") + + # Save full hex to file for analysis + with open('/tmp/signed_tx.hex', 'w') as f: + f.write(tx_hex) + print(f" Full TX saved to /tmp/signed_tx.hex") + + except Exception as e: + print(f" ❌ Signing failed: {e}") + import traceback + traceback.print_exc() + return False + + # Step 11: Verify transaction + print("\nStep 11: Verifying transaction...") + + try: + # Test with local node + result = rpc_call("testmempoolaccept", [[tx_hex]]) + + if result[0]['allowed']: + print(" ✅ Transaction is valid and would be accepted!") + print(f" TXID: {result[0]['txid']}") + else: + print(f" ❌ Transaction rejected: {result[0].get('reject-reason', 'unknown')}") + return False + + except Exception as e: + print(f" ⚠️ Verification failed: {e}") + print(f" This may be normal if using NOWNodes") + + # Step 12: Broadcast + print("\nStep 12: Broadcast transaction?") + print(" This will broadcast to MAINNET!") + response = input(" Type 'YES' (all caps) to broadcast: ") + + if response == 'YES': + try: + # Try NOWNodes first + try: + txid = nownodes_call("sendrawtransaction", [tx_hex]) + print(f" ✅ Transaction broadcast via NOWNodes!") + except: + txid = rpc_call("sendrawtransaction", [tx_hex]) + print(f" ✅ Transaction broadcast via RPC!") + + print(f" TXID: {txid}") + print(f" Explorer: https://zcashblockexplorer.com/transactions/{txid}") + + print("\n" + "=" * 70) + print("🎉 SUCCESS! Transaction is on-chain!") + print("=" * 70) + + except Exception as e: + print(f" ❌ Broadcast failed: {e}") + return False + else: + print(" Skipping broadcast") + + print("\n" + "=" * 70) + print("TEST COMPLETE") + print("=" * 70) + + return True + +if __name__ == "__main__": + try: + success = test_complete_workflow() + sys.exit(0 if success else 1) + except Exception as e: + print(f"\n❌ TEST FAILED: {e}") + import traceback + traceback.print_exc() + sys.exit(1) diff --git a/tests/test_zcash_nu6.py b/tests/test_zcash_nu6.py new file mode 100644 index 00000000..d6c92638 --- /dev/null +++ b/tests/test_zcash_nu6.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +""" +Test Zcash NU6 transaction signing and broadcasting +This test will: +1. Initialize emulator with test mnemonic +2. Get Zcash address +3. Sign a v4 transaction (works with NU6) +4. Broadcast to mainnet +""" + +import sys +import requests +from keepkeylib.client import KeepKeyClient +from keepkeylib.transport_udp import UDPTransport + + +def get_utxos(address): + """Get UTXOs for address from blockchair API""" + url = f"https://api.blockchair.com/zcash/dashboards/address/{address}" + response = requests.get(url) + if response.status_code != 200: + print(f"Error fetching UTXOs: {response.status_code}") + return [] + + data = response.json() + utxos = [] + if 'data' in data and address in data['data']: + addr_data = data['data'][address] + if 'utxo' in addr_data: + for utxo in addr_data['utxo']: + utxos.append({ + 'txid': utxo['transaction_hash'], + 'vout': utxo['index'], + 'value': utxo['value'], + 'confirmations': utxo.get('confirmations', 0) + }) + return utxos + + +def broadcast_transaction(raw_tx_hex): + """Broadcast transaction to Zcash mainnet""" + # Try blockchair first + url = "https://api.blockchair.com/zcash/push/transaction" + response = requests.post(url, json={"data": raw_tx_hex}) + + if response.status_code == 200: + result = response.json() + if 'data' in result and 'transaction_hash' in result['data']: + return True, result['data']['transaction_hash'] + else: + return False, f"Unexpected response: {result}" + else: + return False, f"HTTP {response.status_code}: {response.text}" + + +def main(): + # Connect to emulator + print("Connecting to KeepKey emulator...", flush=True) + transport = UDPTransport('127.0.0.1:11044') + + # Disable passphrase callback to avoid issues + class NoPassphraseClient(KeepKeyClient): + def callback_PassphraseRequest(self, msg): + from keepkeylib import messages_pb2 as proto + return proto.PassphraseAck(passphrase='') + + client = NoPassphraseClient(transport) + + # Check if already initialized + print("Checking device state...", flush=True) + if not client.features.initialized: + # Initialize with test mnemonic (all all all... for testing only) + print("Initializing device...", flush=True) + client.load_device_by_mnemonic( + mnemonic='all all all all all all all all all all all all', + pin='', + passphrase_protection=False, + label='NU6 Test' + ) + else: + print(f"Device already initialized: {client.features.label}", flush=True) + # Try to wipe and reinitialize to ensure clean state + print("Wiping device for clean test...", flush=True) + client.wipe_device() + print("Loading test mnemonic...", flush=True) + client.load_device_by_mnemonic( + mnemonic='all all all all all all all all all all all all', + pin='', + passphrase_protection=False, + label='NU6 Test' + ) + + # Get Zcash address at path m/44'/133'/0'/0/0 + print("\nGetting Zcash address...", flush=True) + address = client.get_address('Zcash', [44 | 0x80000000, 133 | 0x80000000, 0 | 0x80000000, 0, 0]) + print(f"Address: {address}", flush=True) + + # Get UTXOs + print("\nFetching UTXOs...", flush=True) + utxos = get_utxos(address) + + if not utxos: + print("No UTXOs found for this address.", flush=True) + print("You need to send some ZEC to this address first:", flush=True) + print(f" {address}", flush=True) + return 1 + + print(f"Found {len(utxos)} UTXO(s):", flush=True) + for i, utxo in enumerate(utxos): + print(f" [{i}] {utxo['txid']}:{utxo['vout']} - {utxo['value']/100000000} ZEC ({utxo['confirmations']} confirmations)", flush=True) + + # Use first UTXO + utxo = utxos[0] + + # Calculate fee (use 0.0001 ZEC = 10000 satoshis) + fee = 10000 + send_amount = utxo['value'] - fee + + if send_amount <= 0: + print(f"UTXO too small. Need at least {fee} satoshis for fee", flush=True) + return 1 + + print(f"\nCreating transaction:", flush=True) + print(f" Input: {utxo['value']/100000000} ZEC", flush=True) + print(f" Fee: {fee/100000000} ZEC", flush=True) + print(f" Output: {send_amount/100000000} ZEC", flush=True) + print(f" Change address: {address}", flush=True) + + # Sign transaction (v4 format, NU6 branch_id) + print("\nSigning transaction...", flush=True) + + # Create inputs + inputs = [{ + 'prev_hash': bytes.fromhex(utxo['txid'])[::-1], # Reverse byte order + 'prev_index': utxo['vout'], + 'address_n': [44 | 0x80000000, 133 | 0x80000000, 0 | 0x80000000, 0, 0], + 'amount': utxo['value'], + 'script_type': 'SPENDADDRESS' + }] + + # Create outputs (send back to same address as change) + outputs = [{ + 'address': address, + 'amount': send_amount, + 'script_type': 'PAYTOADDRESS' + }] + + # Sign with v4, NU6 branch_id (0xC8E71055) + try: + signatures, serialized_tx = client.sign_tx( + 'Zcash', + inputs, + outputs, + version=4, + version_group_id=0x892F2085, # v4 version group + branch_id=0xC8E71055, # NU6 consensus branch + lock_time=0 + ) + + print(f"\n✅ Transaction signed successfully!") + print(f"Raw transaction: {serialized_tx.hex()}") + + # Broadcast + print("\nBroadcasting to mainnet...") + success, result = broadcast_transaction(serialized_tx.hex()) + + if success: + print(f"\n✅ SUCCESS! Transaction broadcast:") + print(f" TXID: {result}") + print(f" Explorer: https://zcashblockexplorer.com/transactions/{result}") + return 0 + else: + print(f"\n❌ Broadcast failed: {result}") + return 1 + + except Exception as e: + print(f"\n❌ Signing failed: {e}") + import traceback + traceback.print_exc() + return 1 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tests/test_zcash_v5_complete.py b/tests/test_zcash_v5_complete.py new file mode 100755 index 00000000..08efb3c7 --- /dev/null +++ b/tests/test_zcash_v5_complete.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python3 +""" +Complete Zcash v5 (NU6) transaction test with proper scriptPubKey +This test addresses the root cause where firmware needs the actual UTXO's +scriptPubKey for correct ZIP-244 sighash computation. + +Reference: ROOT_CAUSE_ANALYSIS_v2.md +""" +import sys +import os +import binascii +import requests +from hashlib import sha256 + +# Setup paths +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'deps/python-keepkey')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'deps/python-keepkey/tests')) + +import config +from keepkeylib.client import KeepKeyClient, KeepKeyDebuglinkClient +import keepkeylib.messages_pb2 as proto +import keepkeylib.types_pb2 as proto_types +from keepkeylib import tx_api + +tx_api.cache_dir = 'txcache' + +# Zcash node configuration +RPC_URL = os.getenv('ZCASH_RPC_URL', 'http://100.117.181.111:8232') +RPC_USER = os.getenv('ZCASH_RPC_USER', 'zcash') +RPC_PASS = os.getenv('ZCASH_RPC_PASS', '78787ba819a382122e2b4fd98e68db3419ba7cf11c3f22f3bcd07e5ac606e630') + +def rpc_call(method, params=[]): + """Make RPC call to zcashd node""" + payload = { + "jsonrpc": "1.0", + "id": "python", + "method": method, + "params": params + } + response = requests.post( + RPC_URL, + json=payload, + auth=(RPC_USER, RPC_PASS), + timeout=30 + ) + result = response.json() + + if result.get("error"): + raise Exception(f"RPC error: {result['error']}") + + return result["result"] + +def get_utxo_details(txid, vout): + """Get UTXO details including scriptPubKey from blockchain""" + print(f" Fetching UTXO: {txid}:{vout}", flush=True) + + # Get the full transaction (1 = verbose, 0 = hex only) + tx = rpc_call("getrawtransaction", [txid, 1]) + + # Get the specific output + if vout >= len(tx['vout']): + raise Exception(f"Output {vout} not found in transaction") + + output = tx['vout'][vout] + + # Extract scriptPubKey hex + scriptpubkey_hex = output['scriptPubKey']['hex'] + scriptpubkey_bytes = binascii.unhexlify(scriptpubkey_hex) + + # Get amount (in satoshis) + amount = int(output['value'] * 100000000) + + print(f" Amount: {amount} satoshis ({output['value']} ZEC)") + print(f" scriptPubKey: {scriptpubkey_hex}") + + return { + 'amount': amount, + 'scriptpubkey': scriptpubkey_bytes, + 'scriptpubkey_hex': scriptpubkey_hex, + 'address': output['scriptPubKey'].get('addresses', ['unknown'])[0] + } + +def compare_sighashes(firmware_sighash, expected_sighash): + """Compare firmware sighash with expected value""" + print("\n=== SIGHASH COMPARISON ===") + print(f"Firmware: {firmware_sighash}") + print(f"Expected: {expected_sighash}") + + if firmware_sighash == expected_sighash: + print("✅ SIGHASH MATCH!") + return True + else: + print("❌ SIGHASH MISMATCH!") + return False + +def test_v5_signing(): + """Test Zcash v5 transaction signing with proper scriptPubKey""" + + print("=" * 70) + print("ZCASH V5 TRANSACTION SIGNING TEST") + print("=" * 70) + + # Step 1: Connect to emulator + print("\nStep 1: Connecting to KeepKey emulator...") + + # Create transport + transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) + + # Create debug client if debug transport is available + if hasattr(config, 'DEBUG_TRANSPORT'): + debug_transport = config.DEBUG_TRANSPORT(*config.DEBUG_TRANSPORT_ARGS, **config.DEBUG_TRANSPORT_KWARGS) + client = KeepKeyDebuglinkClient(transport) + client.set_debuglink(debug_transport) + else: + client = KeepKeyClient(transport) + + client.set_tx_api(tx_api.TxApiBitcoin) + print(" ✓ Connected") + + # Step 2: Initialize with test mnemonic + print("\nStep 2: Initializing device...") + + # Wipe device first + client.wipe_device() + + # Load mnemonic + client.load_device_by_mnemonic( + mnemonic='all all all all all all all all all all all all', + pin='', + passphrase_protection=False, + label='ZcashV5Test', + language='english' + ) + print(" ✓ Device initialized") + + # Step 3: Get address + print("\nStep 3: Getting Zcash address...") + # Using path m/0/0 for Exodus address + SOURCE_PATH = [0, 0] + address = client.get_address('Zcash', SOURCE_PATH) + print(f" Address: {address}") + + # Step 4: Get current block height for expiry + print("\nStep 4: Getting blockchain info...") + blockchain_info = rpc_call("getblockchaininfo") + current_height = blockchain_info['blocks'] + expiry_height = current_height + 40 + print(f" Current height: {current_height}") + print(f" Expiry height: {expiry_height}") + + # Step 5: Get available UTXOs for the address + print("\nStep 5: Finding UTXOs...") + try: + # Try to get UTXOs using listunspent (accept 0 confirmations for testing) + utxos = rpc_call("listunspent", [0, 9999999, [address]]) + if not utxos: + print(f" ❌ No UTXOs found for {address}") + print(" Please send some testnet ZEC to this address first") + return False + except Exception as e: + print(f" ❌ Error fetching UTXOs: {e}") + return False + + # Sort by confirmations (prefer confirmed UTXOs to avoid getrawtransaction issues) + utxos.sort(key=lambda x: x.get('confirmations', 0), reverse=True) + + # Use first UTXO (most confirmed) + utxo = utxos[0] + print(f" ✓ Found {len(utxos)} UTXO(s), using most confirmed one") + print(f" TXID: {utxo['txid']}") + print(f" VOUT: {utxo['vout']}") + print(f" Amount: {utxo['amount']} ZEC") + print(f" Confirmations: {utxo.get('confirmations', 0)}") + + # Step 6: Get detailed UTXO info including scriptPubKey + print("\nStep 6: Fetching UTXO details...") + utxo_details = get_utxo_details(utxo['txid'], utxo['vout']) + + # Step 7: Create transaction inputs with scriptPubKey + print("\nStep 7: Creating transaction inputs...") + + UTXO_TXID = utxo['txid'] + UTXO_VOUT = utxo['vout'] + UTXO_AMOUNT = utxo_details['amount'] + UTXO_SCRIPTPUBKEY = utxo_details['scriptpubkey'] + + # CRITICAL: Provide the actual UTXO's scriptPubKey for ZIP-244 signing + inp1 = proto_types.TxInputType( + address_n=SOURCE_PATH, + prev_hash=binascii.unhexlify(UTXO_TXID), + prev_index=UTXO_VOUT, + amount=UTXO_AMOUNT, + script_pubkey=UTXO_SCRIPTPUBKEY # ← This is the critical fix! + ) + + print(f" ✓ Input created with scriptPubKey: {utxo_details['scriptpubkey_hex']}") + + # Step 8: Create transaction outputs + print("\nStep 8: Creating transaction outputs...") + + # Calculate amounts based on UTXO size + FEE = 10000 # 0.0001 ZEC (standard fee) + SEND_AMOUNT = (UTXO_AMOUNT - FEE) // 2 # Send half, keep half as change + CHANGE_AMOUNT = UTXO_AMOUNT - SEND_AMOUNT - FEE + + DEST_ADDRESS = "t1d3URKgTufDFhEr8pxm388kVjw1V4Ba1Ez" + + out1 = proto_types.TxOutputType( + address=DEST_ADDRESS, + amount=SEND_AMOUNT, + script_type=proto_types.PAYTOADDRESS, + ) + + out2 = proto_types.TxOutputType( + address=address, # Change back to source + amount=CHANGE_AMOUNT, + script_type=proto_types.PAYTOADDRESS, + ) + + print(f" Output 1: {SEND_AMOUNT/100000000} ZEC to {DEST_ADDRESS}") + print(f" Output 2: {CHANGE_AMOUNT/100000000} ZEC (change) to {address}") + print(f" Fee: {FEE/100000000} ZEC") + + # Step 9: Sign transaction with v5 format + print("\nStep 9: Signing transaction (version 5)...") + + try: + (signatures, serialized_tx) = client.sign_tx( + 'Zcash', + [inp1], + [out1, out2], + version=5, # ← Use v5 for NU6 + lock_time=0, + expiry=expiry_height + ) + + tx_hex = binascii.hexlify(serialized_tx).decode('ascii') + print(f" ✓ Transaction signed successfully!") + print(f" Transaction length: {len(serialized_tx)} bytes") + print(f" TX hex: {tx_hex[:100]}...") + + except Exception as e: + print(f" ❌ Signing failed: {e}") + return False + + # Step 10: Read firmware debug output + print("\nStep 10: Reading firmware debug output...") + firmware_sighash = None + if os.path.exists('/tmp/zip244_debug.txt'): + with open('/tmp/zip244_debug.txt', 'r') as f: + debug_output = f.read() + print("=== FIRMWARE ZIP-244 DEBUG OUTPUT ===") + print(debug_output) + + # Extract sighash from debug output + for line in debug_output.split('\n'): + if line.startswith('signature_digest:'): + firmware_sighash = line.split(':')[1].strip() + break + else: + print(" ⚠️ Debug file not found at /tmp/zip244_debug.txt") + + # Step 11: Decode transaction to verify structure + print("\nStep 11: Decoding transaction structure...") + try: + decoded = rpc_call("decoderawtransaction", [tx_hex]) + print(f" ✓ Transaction decoded successfully") + print(f" Version: {decoded['version']}") + print(f" Inputs: {len(decoded['vin'])}") + print(f" Outputs: {len(decoded['vout'])}") + print(f" Lock time: {decoded['locktime']}") + print(f" Expiry: {decoded.get('expiryheight', 'N/A')}") + except Exception as e: + print(f" ❌ Failed to decode transaction: {e}") + return False + + # Step 12: Broadcast transaction (the ultimate validation!) + print("\nStep 12: Broadcast transaction to network?") + print(f" This will send a real transaction to the Zcash network!") + response = input(" Type 'yes' to broadcast: ") + + if response.lower() == 'yes': + try: + txid = rpc_call("sendrawtransaction", [tx_hex]) + print(f" ✅ Transaction broadcast successfully!") + print(f" TXID: {txid}") + print(f" Explorer: https://zcashblockexplorer.com/transactions/{txid}") + except Exception as e: + print(f" ❌ Broadcast failed: {e}") + return False + else: + print(" Skipping broadcast") + + print("\n" + "=" * 70) + print("TEST COMPLETE") + print("=" * 70) + + return True + +if __name__ == "__main__": + try: + success = test_v5_signing() + sys.exit(0 if success else 1) + except Exception as e: + print(f"\n❌ TEST FAILED: {e}") + import traceback + traceback.print_exc() + sys.exit(1) diff --git a/tests/verify_zip244.py b/tests/verify_zip244.py new file mode 100644 index 00000000..341cdd9d --- /dev/null +++ b/tests/verify_zip244.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +Verify ZIP-244 sighash calculation matches firmware output +""" +import hashlib + +def blake2b_256(data, personalization): + """BLAKE2b-256 with personalization""" + h = hashlib.blake2b(digest_size=32, person=personalization) + h.update(data) + return h.digest() + +# From debug output +branch_id = 0xC8E71055 +version = 0x00000005 +version_group_id = 0x26A7270A +lock_time = 0 +expiry = 3109060 # 0x002F7054 + +# Convert to bytes (little-endian) +branch_id_bytes = branch_id.to_bytes(4, 'little') +version_bytes = version.to_bytes(4, 'little') +version_group_id_bytes = version_group_id.to_bytes(4, 'little') +lock_time_bytes = lock_time.to_bytes(4, 'little') +expiry_bytes = expiry.to_bytes(4, 'little') + +print("=== ZIP-244 VERIFICATION ===\n") +print(f"branch_id: 0x{branch_id:08X} ({branch_id})") +print(f"version: 0x{version:08X}") +print(f"version_group_id: 0x{version_group_id:08X}") +print(f"lock_time: {lock_time}") +print(f"expiry: {expiry}") +print() + +# 1. Compute header_digest +TX_OVERWINTERED = 0x80000000 +header = (version | TX_OVERWINTERED).to_bytes(4, 'little') +header_data = header + version_group_id_bytes + branch_id_bytes + lock_time_bytes + expiry_bytes + +header_digest = blake2b_256(header_data, b"ZTxIdHeadersHash") +print(f"header_digest: {header_digest.hex()}") +print(f"Expected: 7b404ac23f1926eed96230b5ea0c10b457a68bf2e48e25531b3f9ca8c22197a5") +print(f"Match: {header_digest.hex() == '7b404ac23f1926eed96230b5ea0c10b457a68bf2e48e25531b3f9ca8c22197a5'}") +print() + +# 2. Compute txin_sig_digest +prevout_txid = bytes.fromhex("c23b78951c3598b0e6f97c2cde00728d7ef076fcd41b9fa49660980e6c2c34b1") +prevout_index = 1 +scriptCode = bytes.fromhex("76a914d5839f38efa1de7073576dceb74bb60b2e1ddc7788ac") +amount = 3626650 +sequence = 0xFFFFFFFF + +# Build txin_digest data +txin_data = b"" +txin_data += prevout_txid # 32 bytes (already in little-endian/internal format from debug) +txin_data += prevout_index.to_bytes(4, 'little') +txin_data += len(scriptCode).to_bytes(1, 'little') # CompactSize (< 253) +txin_data += scriptCode +txin_data += amount.to_bytes(8, 'little') +txin_data += sequence.to_bytes(4, 'little') + +txin_digest = blake2b_256(txin_data, b"Zcash___TxInHash") +print(f"txin_digest: {txin_digest.hex()}") +print(f"Expected: 0e445070d44209ef9f48b4556d183a62d3b1ea95f9475642e624d02fa6dfdc42") +print(f"Match: {txin_digest.hex() == '0e445070d44209ef9f48b4556d183a62d3b1ea95f9475642e624d02fa6dfdc42'}") +print() + +# 3. Compute transparent_sig_digest +prevouts_digest = bytes.fromhex("61f7c0bf963cb836f9d5ea054f00664fe4e5f8bbf137ed3f155e937a444d61de") +sequence_digest = bytes.fromhex("bbfae845a18fce3146d3a322aac622b61bd055bfa00ac9c2a4db82ceb37ff987") +outputs_digest = bytes.fromhex("73dd65cacbd145128e26776b5dc53e61d2a756f19d285f2facf83b619bf3767c") + +transparent_data = prevouts_digest + sequence_digest + outputs_digest + txin_digest +transparent_sig_digest = blake2b_256(transparent_data, b"ZTxIdTranspaHash") +print(f"transparent_sig_digest: {transparent_sig_digest.hex()}") +print(f"Expected: 855a795a69938dda876660fa4ca25093d132b92ddb0bb50188fc07f02ed202f5") +print(f"Match: {transparent_sig_digest.hex() == '855a795a69938dda876660fa4ca25093d132b92ddb0bb50188fc07f02ed202f5'}") +print() + +# 4. Compute final signature_digest +sig_personal = b"ZcashTxHash_" + branch_id_bytes +sapling_digest = bytes(32) # all zeros +orchard_digest = bytes(32) # all zeros + +sig_data = header_digest + transparent_sig_digest + sapling_digest + orchard_digest +signature_digest = blake2b_256(sig_data, sig_personal) +print(f"signature_digest: {signature_digest.hex()}") +print(f"Expected: 8e8455e4f6e4157ea5f62e527eea111f7fb8b41fae654f951ea76d09c5009394") +print(f"Match: {signature_digest.hex() == '8e8455e4f6e4157ea5f62e527eea111f7fb8b41fae654f951ea76d09c5009394'}") +print() + +print("\n=== VERIFICATION COMPLETE ===") +print("All components match the firmware output!") +print("\nThis means the ZIP-244 sighash calculation is correct.") +print("The broadcast failure must be due to a different issue.") +print("\nPossible causes:") +print("1. Transaction structure (version, inputs, outputs)") +print("2. ScriptSig formatting") +print("3. Public key mismatch") +print("4. Wrong sighash type byte") diff --git a/tests/zcash_rpc.py b/tests/zcash_rpc.py new file mode 100755 index 00000000..83bd6a63 --- /dev/null +++ b/tests/zcash_rpc.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +""" +Zcash RPC client for firmware testing +""" + +import requests +import json +import sys + + +class ZcashRPC: + def __init__(self): + self.url = "http://100.117.181.111:8232" + self.auth = ("zcash", "78787ba819a382122e2b4fd98e68db3419ba7cf11c3f22f3bcd07e5ac606e630") + + def call(self, method, params=[]): + """Make RPC call to Zcash node""" + payload = { + "jsonrpc": "1.0", + "id": "python", + "method": method, + "params": params + } + response = requests.post(self.url, json=payload, auth=self.auth) + result = response.json() + + if result.get("error"): + raise Exception(f"RPC Error: {result['error']}") + + return result["result"] + + def broadcast_transaction(self, tx_hex): + """Broadcast a signed transaction""" + return self.call("sendrawtransaction", [tx_hex]) + + def decode_transaction(self, tx_hex): + """Decode transaction hex to readable format""" + return self.call("decoderawtransaction", [tx_hex]) + + def get_blockchain_info(self): + """Get current blockchain status""" + return self.call("getblockchaininfo") + + def get_transaction(self, txid, verbose=True): + """Fetch transaction by TXID""" + return self.call("getrawtransaction", [txid, 1 if verbose else 0]) + + def validate_address(self, address): + """Validate a Zcash address""" + return self.call("validateaddress", [address]) + + def get_network_info(self): + """Get network information""" + return self.call("getnetworkinfo") + + +def main(): + """Example usage""" + rpc = ZcashRPC() + + print("Zcash Node Status") + print("=" * 60) + + # Get blockchain info + info = rpc.get_blockchain_info() + print(f"Current Height: {info['blocks']:,}") + print(f"Chain: {info['chain']}") + print(f"Verification Progress: {info['verificationprogress']:.2%}") + + # Get network info + net_info = rpc.get_network_info() + print(f"\nNode Version: {net_info['subversion']}") + print(f"Protocol Version: {net_info['protocolversion']}") + print(f"Connections: {net_info['connections']}") + + # Network upgrades + print("\nNetwork Upgrades:") + print("-" * 60) + upgrades = info['upgrades'] + for branch_id, upgrade_info in upgrades.items(): + status = upgrade_info['status'] + name = upgrade_info['name'] + height = upgrade_info.get('activationheight', 'N/A') + emoji = '✅' if status == 'active' else '⏳' if status == 'pending' else '📦' + print(f"{emoji} {name:12} (0x{branch_id}) - Height {height:>8} - {status.upper()}") + + +if __name__ == "__main__": + try: + main() + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1)