diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 16c4bedb..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,85 +0,0 @@ -version: 2 # keep 2.0 syntax; CircleCI 2.1 also works - -jobs: - emulator-build-test: - docker: - - image: circleci/python:3.7 # upgrade to cimg/python:3.12 if you like - steps: - # ──────────────────────────────────────────────────────────────── - # 1) Clone the current branch of python-keepkey via HTTPS - # ──────────────────────────────────────────────────────────────── - - run: - name: Clone python-keepkey (current branch) - command: | - git clone --depth 1 -b "$CIRCLE_BRANCH" \ - "https://github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git" .pykk - cd .pykk && git submodule update --init --recursive - - # ──────────────────────────────────────────────────────────────── - # 2) Grab firmware repo and inject our fresh python-keepkey copy - # ──────────────────────────────────────────────────────────────── - - run: - name: Checkout firmware & inject python-keepkey - command: | - # Ensure all submodule URLs fall back to HTTPS - git config --global url."https://github.com/".insteadOf git@github.com: - git config --global url."https://".insteadOf git:// - - # Move python-keepkey out of the way - mv .pykk ../ - - # Test the same exact companion implementation as the GitHub - # Actions integration lane. Bump deliberately with that workflow. - git init . - git remote add origin https://github.com/BitHighlander/keepkey-firmware.git - git fetch --depth 1 origin e07a95e7d069553c273b24552c9bc436f60f5d91 - git checkout --detach FETCH_HEAD - - # Initialise firmware submodules - git submodule update --init --recursive - - # Replace the vendor copy with our PR branch python-keepkey - rm -rf deps/python-keepkey - mv ../.pykk deps/python-keepkey - - # ──────────────────────────────────────────────────────────────── - # 3) Build the Docker-based emulator tests - # ──────────────────────────────────────────────────────────────── - - setup_remote_docker - - - run: - name: Emulator tests - command: | - pushd ./scripts/emulator - set +e # don’t exit on first failure - docker-compose up --build python-keepkey - set -e - - # Collect JUnit / pytest XML results - mkdir -p ../../test-reports - docker cp "$(docker-compose ps -q firmware-unit)":/kkemu/test-reports/. ../../test-reports/ - docker cp "$(docker-compose ps -q python-keepkey)":/kkemu/test-reports/. ../../test-reports/ - popd - - # python-keepkey depends on firmware-unit in the pinned firmware's - # compose graph, so both suites run and both results gate this job. - # Read each status file defensively: a container crash before the - # file exists must fail rather than silently pass an empty value. - for SUITE in python-keepkey firmware-unit; do - STATUS_FILE="test-reports/$SUITE/status" - if [ ! -f "$STATUS_FILE" ]; then - echo "no status file at $STATUS_FILE -- the suite did not finish" - exit 1 - fi - [ "$(cat "$STATUS_FILE")" = "0" ] || exit 1 - done - - - store_test_results: - path: test-reports - -# ────────────────────────────────────────────────────────────────────── -workflows: - version: 2 - emulator: - jobs: - - emulator-build-test diff --git a/.circleci/standalone-emulator-tests.sh b/.circleci/standalone-emulator-tests.sh new file mode 100755 index 00000000..96f0aa24 --- /dev/null +++ b/.circleci/standalone-emulator-tests.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +# python-keepkey's own CI is a compatibility test against the emulator supplied +# by the firmware checkout. It deliberately does not produce OLED/PDF release +# evidence. Authoritative display evidence is generated by keepkey-firmware CI, +# which pins both repositories to exact candidate SHAs. + +mkdir -p /kkemu/test-reports/python-keepkey + +echo "=== Waiting for emulator ===" +for attempt in $(seq 1 20); do + if echo -n "PINGPING" | nc -u -w1 kkemu 11044 2>/dev/null | grep -q PONG; then + echo "Emulator ready (attempt $attempt)" + break + fi + if [ "$attempt" -eq 20 ]; then + echo "Emulator did not become ready" + echo "1" > /kkemu/test-reports/python-keepkey/status + exit 1 + fi + sleep 2 +done + +cd /kkemu/deps/python-keepkey/tests +set +e +KK_TRANSPORT_MAIN=kkemu:11044 \ +KK_TRANSPORT_DEBUG=kkemu:11045 \ +pytest -v --tb=short \ + --junitxml=/kkemu/test-reports/python-keepkey/junit.xml +pytest_status=$? +set -e + +echo "$pytest_status" > /kkemu/test-reports/python-keepkey/status +exit "$pytest_status" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25c72b34..17a624cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,23 +1,21 @@ # KeepKey python-keepkey CI # -# Pulls the published emulator image (kktech/kkemu) from DockerHub -# and runs the full python integration test suite against it. +# Builds both fork release candidates from immutable commits and runs this +# exact Python head against their regular and Bitcoin-only product surfaces. # # Stage 1: GATE (seconds) # └─ lint Python syntax + deterministic protocol contract tests # # Stage 2: TEST (gated by Stage 1) -# ├─ integration full pytest suite against the regular emulator (7.16) -# ├─ integration-btc bitcoin-only product boundary against a -# │ -DKK_BITCOIN_ONLY=ON emulator (7.16) -# └─ integration-rc18 the same suite against RC18/7.15.0, a blocking -# release-target compatibility gate +# ├─ integration full suite against regular 7.15 +# ├─ integration-7143 full suite against regular 7.14.3 +# └─ integration-btc Bitcoin-only boundary against both candidates name: CI on: push: - branches: [master, develop, reconcile/upstream-sync, 'feature/**', 'fix/**', 'hotfix/**'] + branches: [master, develop, 'reconcile/**', 'feature/**', 'fix/**', 'hotfix/**'] pull_request: branches: [master, develop, reconcile/upstream-sync] @@ -76,6 +74,9 @@ jobs: tests/test_clearsign_abi.py \ tests/test_token_table_generators.py + - name: Verify offline transaction fixture manifest + run: python tests/tx_fixture_manifest.py --check + - name: Lint summary run: | echo "## 🔑 KeepKey python-keepkey — Lint" >> "$GITHUB_STEP_SUMMARY" @@ -86,9 +87,13 @@ jobs: echo "| Zcash PCZT contract | ✅ PASS |" >> "$GITHUB_STEP_SUMMARY" echo "| ABI encoder | ✅ PASS |" >> "$GITHUB_STEP_SUMMARY" echo "| Token-table generators | ✅ PASS |" >> "$GITHUB_STEP_SUMMARY" + echo "| Offline fixture integrity | ✅ PASS |" >> "$GITHUB_STEP_SUMMARY" + FIXTURE_SHA=$(sha256sum tests/txcache/manifest.json | cut -d' ' -f1) + echo "" >> "$GITHUB_STEP_SUMMARY" + printf 'Fixture manifest SHA-256: `%s`\n' "$FIXTURE_SHA" >> "$GITHUB_STEP_SUMMARY" # ═══════════════════════════════════════════════════════════ - # STAGE 2: TEST — pull published emulator, run pytest + # STAGE 2: TEST — build exact candidate emulators, run pytest # ═══════════════════════════════════════════════════════════ integration: @@ -114,8 +119,8 @@ jobs: submodules: recursive path: python-keepkey - # python-keepkey is a SUBMODULE of the firmware repo, so the firmware is - # where the emulator lives. alpha is the fork's integration branch. + # Immutable fork 7.15 candidate. Once canonical Python merges, the + # firmware branch is repinned to that one upstream commit and rerun. - name: Checkout firmware uses: actions/checkout@v4 with: @@ -131,7 +136,7 @@ jobs: # integration-btc job) and the Ironwood known-answer vectors. So this # job validates 7.16.0; it does not validate the RC18 dependency # graph. Bump deliberately, and re-read that claim when you do. - ref: e07a95e7d069553c273b24552c9bc436f60f5d91 + ref: 651f2a462b8e71ffb37995094dbe1e9298bc802f path: keepkey-firmware # NOT `submodules: recursive`. trezor-firmware carries a micropython @@ -177,20 +182,27 @@ jobs: pip install --upgrade pip pip install "protobuf>=3.20,<4" pip install -e . - pip install pytest semver rlp requests eth-keys pycryptodome + pip install pytest pytest-timeout semver rlp requests eth-keys pycryptodome - name: Wait for emulator run: | echo "Waiting for emulator bridge on port 5000..." + ready=false for i in $(seq 1 30); do if curl -sf -X POST http://localhost:5000/exchange/main \ -H 'Content-Type: application/json' \ -d '{"data":""}' > /dev/null 2>&1; then echo "Emulator ready after ${i}s" + ready=true break fi sleep 1 done + [ "$ready" = true ] || { + docker logs kkemu + echo "FATAL: emulator bridge did not become ready" >&2 + exit 1 + } # "The emulator answered a ping" is not "the emulator is the right # firmware". CI ran a 7.16-era suite against a 7.10.0 image for five @@ -237,6 +249,7 @@ jobs: KK_TRANSPORT_MAIN: "127.0.0.1:11044" KK_TRANSPORT_DEBUG: "127.0.0.1:11045" PYTHONPATH: "${{ github.workspace }}/keepkey-firmware/deps/python-keepkey" + PYTHONUNBUFFERED: "1" # A crashed emulator now raises instead of blocking in recv() forever. KK_UDP_TIMEOUT: "45" run: | @@ -246,6 +259,17 @@ jobs: # firmware and they resolve; run them standalone and they fail # claiming the sources are missing. cd keepkey-firmware/deps/python-keepkey/tests + python tx_fixture_manifest.py --check + EMULATOR_IP=$(docker inspect -f \ + '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' kkemu) + test -n "$EMULATOR_IP" + sudo iptables -I OUTPUT 1 -d "$EMULATOR_IP" -j ACCEPT + sudo iptables -I OUTPUT 2 ! -o lo -m conntrack --ctstate NEW -j REJECT + cleanup_network_gate() { + sudo iptables -D OUTPUT ! -o lo -m conntrack --ctstate NEW -j REJECT + sudo iptables -D OUTPUT -d "$EMULATOR_IP" -j ACCEPT + } + trap cleanup_network_gate EXIT pytest -v --junitxml=junit.xml 2>&1 | tee pytest-output.txt echo "${PIPESTATUS[0]}" > status @@ -253,8 +277,14 @@ jobs: if: always() run: | XML="keepkey-firmware/deps/python-keepkey/tests/junit.xml" + MANIFEST="keepkey-firmware/deps/python-keepkey/tests/txcache/manifest.json" echo "## 🔑 KeepKey python-keepkey — Integration Tests" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" + if [ -f "$MANIFEST" ]; then + FIXTURE_SHA=$(sha256sum "$MANIFEST" | cut -d' ' -f1) + printf 'Fixture manifest SHA-256: `%s`\n' "$FIXTURE_SHA" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + fi if [ ! -f "$XML" ]; then echo "❌ **No test results found** — suite may have crashed before completion." >> "$GITHUB_STEP_SUMMARY" @@ -321,27 +351,16 @@ jobs: [ "$STATUS" = "0" ] || exit 1 # ═══════════════════════════════════════════════════════════ - # STAGE 2c: TEST — the RELEASE TARGET (RC18 / 7.15.0) + # STAGE 2c: TEST — the 7.14.3 release candidate # ═══════════════════════════════════════════════════════════ - integration-rc18: + integration-7143: needs: [lint] runs-on: ubuntu-latest timeout-minutes: 15 - # The other two integration jobs pin firmware 7.16.0, because parts of - # this suite need firmware that postdates RC18: variant_getName() - # returning "EmulatorBTC", and the Ironwood known-answer vectors. A green - # run there says nothing about the release this PR targets. - # - # This job closes that gap by actually running the suite against - # RC18/7.15.0. The current-head suite is green against that exact image, so - # this is a blocking release gate: a regression from green is a real - # failure. - # - # Tests that need post-RC18 firmware skip themselves here rather than - # failing. Their gates are tied to the implementation history, so RC18 is - # not credited with behavior it never shipped. + # Run the complete merged Python suite against the immutable fork 7.14.3 + # candidate before canonical Python is merged upstream. steps: - uses: actions/checkout@v4 @@ -349,14 +368,11 @@ jobs: submodules: recursive path: python-keepkey - - name: Checkout firmware (RC18) + - name: Checkout firmware (7.14.3) uses: actions/checkout@v4 with: repository: BitHighlander/keepkey-firmware - # v7.15.0-rc18 final audit candidate -- the head of - # audit/7.15.0-rc18-final, merged as firmware PR #320. This is the - # release this PR is cut against. - ref: fd1012c5adbacf88e2ca521a95b335a2849d528f + ref: 4125e1c7409b1cb7b08ba595bc408e3128fc24ca path: keepkey-firmware - name: Init the submodules the emulator build needs @@ -373,18 +389,18 @@ jobs: rm -rf keepkey-firmware/deps/python-keepkey cp -a python-keepkey keepkey-firmware/deps/python-keepkey - - name: Build the RC18 emulator + - name: Build the 7.14.3 emulator timeout-minutes: 20 working-directory: keepkey-firmware run: | - docker build -t kkemu-rc18-ci -f scripts/emulator/Dockerfile . + docker build -t kkemu-7143-ci -f scripts/emulator/Dockerfile . - name: Start the emulator run: | - docker run -d --name kkemu-rc18 \ - -p 11044:11044/udp -p 11045:11045/udp -p 5000:5000 kkemu-rc18-ci + docker run -d --name kkemu-7143 \ + -p 11044:11044/udp -p 11045:11045/udp -p 5000:5000 kkemu-7143-ci sleep 3 - docker logs kkemu-rc18 | head -5 + docker logs kkemu-7143 | head -5 - uses: actions/setup-python@v5 with: @@ -396,25 +412,32 @@ jobs: pip install --upgrade pip pip install "protobuf>=3.20,<4" pip install -e . - pip install pytest semver rlp requests eth-keys pycryptodome + pip install pytest pytest-timeout semver rlp requests eth-keys pycryptodome - name: Wait for emulator run: | echo "Waiting for emulator bridge on port 5000..." + ready=false for i in $(seq 1 30); do if curl -sf -X POST http://localhost:5000/exchange/main \ -H 'Content-Type: application/json' \ -d '{"data":""}' > /dev/null 2>&1; then echo "Emulator ready after ${i}s" + ready=true break fi sleep 1 done + [ "$ready" = true ] || { + docker logs kkemu-7143 + echo "FATAL: emulator bridge did not become ready" >&2 + exit 1 + } - # Assert this really is 7.15.0. A silently-wrong ref would make this job + # Assert this really is 7.14.3. A silently-wrong ref would make this job # a duplicate of `integration` and quietly retire the gap it exists to # measure. - - name: Assert the emulator is RC18 + - name: Assert the emulator is 7.14.3 timeout-minutes: 2 env: KK_TRANSPORT_MAIN: "127.0.0.1:11044" @@ -435,12 +458,12 @@ jobs: f = c.features got = (f.major_version, f.minor_version, f.patch_version) print('emulator firmware %d.%d.%d, variant %r' % (got + (f.firmware_variant,))) - if got != (7, 15, 0): - sys.exit('FATAL: expected RC18 (7.15.0), got %d.%d.%d -- the pinned ' + if got != (7, 14, 3): + sys.exit('FATAL: expected 7.14.3, got %d.%d.%d -- the pinned ' 'firmware ref is not the release target.' % got) PY - - name: Run the suite against RC18 + - name: Run the suite against 7.14.3 timeout-minutes: 10 env: KK_TRANSPORT_MAIN: "127.0.0.1:11044" @@ -449,17 +472,34 @@ jobs: KK_UDP_TIMEOUT: "45" run: | cd keepkey-firmware/deps/python-keepkey/tests - pytest -v --junitxml=junit-rc18.xml 2>&1 | tee pytest-rc18-output.txt - echo "${PIPESTATUS[0]}" > status-rc18 - - - name: RC18 summary + python tx_fixture_manifest.py --check + EMULATOR_IP=$(docker inspect -f \ + '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' kkemu-7143) + test -n "$EMULATOR_IP" + sudo iptables -I OUTPUT 1 -d "$EMULATOR_IP" -j ACCEPT + sudo iptables -I OUTPUT 2 ! -o lo -m conntrack --ctstate NEW -j REJECT + cleanup_network_gate() { + sudo iptables -D OUTPUT ! -o lo -m conntrack --ctstate NEW -j REJECT + sudo iptables -D OUTPUT -d "$EMULATOR_IP" -j ACCEPT + } + trap cleanup_network_gate EXIT + pytest -v --junitxml=junit-7143.xml 2>&1 | tee pytest-7143-output.txt + echo "${PIPESTATUS[0]}" > status-7143 + + - name: 7.14.3 summary if: always() run: | - XML="keepkey-firmware/deps/python-keepkey/tests/junit-rc18.xml" - echo "## 🔑 python-keepkey — RC18 / 7.15.0" >> "$GITHUB_STEP_SUMMARY" + XML="keepkey-firmware/deps/python-keepkey/tests/junit-7143.xml" + MANIFEST="keepkey-firmware/deps/python-keepkey/tests/txcache/manifest.json" + echo "## 🔑 python-keepkey — 7.14.3" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" echo "Blocking release-target compatibility gate." >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" + if [ -f "$MANIFEST" ]; then + FIXTURE_SHA=$(sha256sum "$MANIFEST" | cut -d' ' -f1) + printf 'Fixture manifest SHA-256: `%s`\n' "$FIXTURE_SHA" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + fi if [ ! -f "$XML" ]; then echo "❌ **No test results** — the suite crashed before completion." >> "$GITHUB_STEP_SUMMARY" else @@ -478,32 +518,32 @@ jobs: echo "| 💥 Errors | $ERRORS |" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" if [ "$FAILED" -eq 0 ] && [ "$ERRORS" -eq 0 ]; then - echo "RC18 is green at current head." >> "$GITHUB_STEP_SUMMARY" + echo "7.14.3 is green at current head." >> "$GITHUB_STEP_SUMMARY" else - echo "RC18 compatibility failed at current head." >> "$GITHUB_STEP_SUMMARY" + echo "7.14.3 compatibility failed at current head." >> "$GITHUB_STEP_SUMMARY" fi fi - - name: Annotate RC18 results + - name: Annotate 7.14.3 results uses: mikepenz/action-junit-report@v4 if: always() with: - report_paths: keepkey-firmware/deps/python-keepkey/tests/junit-rc18.xml + report_paths: keepkey-firmware/deps/python-keepkey/tests/junit-7143.xml annotate_only: true require_tests: true fail_on_failure: false # `pytest | tee` makes the run step exit with tee's status, so without - # this the job reports success no matter what RC18 did. This step makes a + # this the job reports success no matter what 7.14.3 did. This step makes a # real pytest failure fail the blocking release gate. - - name: Report the RC18 result + - name: Report the 7.14.3 result if: always() run: | - STATUS=$(cat keepkey-firmware/deps/python-keepkey/tests/status-rc18 2>/dev/null || echo "1") + STATUS=$(cat keepkey-firmware/deps/python-keepkey/tests/status-7143 2>/dev/null || echo "1") if [ "$STATUS" = "0" ]; then - echo "RC18 suite passed." + echo "7.14.3 suite passed." else - echo "::error::RC18 (7.15.0) compatibility failed; see the summary." + echo "::error::7.14.3 compatibility failed; see the summary." exit 1 fi @@ -512,9 +552,20 @@ jobs: # ═══════════════════════════════════════════════════════════ integration-btc: + name: integration-btc (${{ matrix.release }}) needs: [lint] runs-on: ubuntu-latest timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - release: "7.14.3" + firmware_ref: 4125e1c7409b1cb7b08ba595bc408e3128fc24ca + min_fw: "7.14.3" + - release: "7.15" + firmware_ref: d33f1711c3b2b205f64c5dc35fdec02926a6dc63 + min_fw: "7.15.0" # KK_BITCOIN_ONLY=ON is a second shipping product, not a build flavour: # coins.def keeps only Bitcoin and Testnet, messagemap.def drops every @@ -550,7 +601,7 @@ jobs: # integration-btc job) and the Ironwood known-answer vectors. So this # job validates 7.16.0; it does not validate the RC18 dependency # graph. Bump deliberately, and re-read that claim when you do. - ref: e07a95e7d069553c273b24552c9bc436f60f5d91 + ref: 651f2a462b8e71ffb37995094dbe1e9298bc802f path: keepkey-firmware # Same non-recursive init as the regular job: trezor-firmware's @@ -598,20 +649,27 @@ jobs: pip install --upgrade pip pip install "protobuf>=3.20,<4" pip install -e . - pip install pytest semver rlp requests eth-keys pycryptodome + pip install pytest pytest-timeout semver rlp requests eth-keys pycryptodome - name: Wait for emulator run: | echo "Waiting for emulator bridge on port 5000..." + ready=false for i in $(seq 1 30); do if curl -sf -X POST http://localhost:5000/exchange/main \ -H 'Content-Type: application/json' \ -d '{"data":""}' > /dev/null 2>&1; then echo "Emulator ready after ${i}s" + ready=true break fi sleep 1 done + [ "$ready" = true ] || { + docker logs kkemu-btc + echo "FATAL: emulator bridge did not become ready" >&2 + exit 1 + } # A bitcoin-only emulator that reports "Emulator" instead of # "EmulatorBTC" makes requires_bitcoinOnly() skip the whole file, and a @@ -622,7 +680,7 @@ jobs: env: KK_TRANSPORT_MAIN: "127.0.0.1:11044" KK_TRANSPORT_DEBUG: "127.0.0.1:11045" - KK_MIN_FW: "7.15.0" + KK_MIN_FW: "${{ matrix.min_fw }}" KK_UDP_TIMEOUT: "20" working-directory: keepkey-firmware/deps/python-keepkey/tests run: | @@ -659,6 +717,17 @@ jobs: KK_UDP_TIMEOUT: "45" run: | cd keepkey-firmware/deps/python-keepkey/tests + python tx_fixture_manifest.py --check + EMULATOR_IP=$(docker inspect -f \ + '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' kkemu-btc) + test -n "$EMULATOR_IP" + sudo iptables -I OUTPUT 1 -d "$EMULATOR_IP" -j ACCEPT + sudo iptables -I OUTPUT 2 ! -o lo -m conntrack --ctstate NEW -j REJECT + cleanup_network_gate() { + sudo iptables -D OUTPUT ! -o lo -m conntrack --ctstate NEW -j REJECT + sudo iptables -D OUTPUT -d "$EMULATOR_IP" -j ACCEPT + } + trap cleanup_network_gate EXIT pytest -v --junitxml=junit-btc.xml test_msg_bitcoin_only_variant.py \ 2>&1 | tee pytest-btc-output.txt echo "${PIPESTATUS[0]}" > status-btc @@ -695,8 +764,14 @@ jobs: if: always() run: | XML="keepkey-firmware/deps/python-keepkey/tests/junit-btc.xml" + MANIFEST="keepkey-firmware/deps/python-keepkey/tests/txcache/manifest.json" echo "## 🔑 KeepKey python-keepkey — Bitcoin-only product boundary" >> "$GITHUB_STEP_SUMMARY" echo "" >> "$GITHUB_STEP_SUMMARY" + if [ -f "$MANIFEST" ]; then + FIXTURE_SHA=$(sha256sum "$MANIFEST" | cut -d' ' -f1) + printf 'Fixture manifest SHA-256: `%s`\n' "$FIXTURE_SHA" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + fi if [ ! -f "$XML" ]; then echo "❌ **No test results found** — suite may have crashed." >> "$GITHUB_STEP_SUMMARY" else diff --git a/docs/handoff-python-test-hermeticity.md b/docs/handoff-python-test-hermeticity.md new file mode 100644 index 00000000..f32cbf99 --- /dev/null +++ b/docs/handoff-python-test-hermeticity.md @@ -0,0 +1,114 @@ +# Handoff: authoritative python-keepkey tests must be fully offline + +## Non-negotiable release rule + +The authoritative Python suite must never depend on an explorer, RPC service, +DNS, TLS, remote retention, or the caller's working directory. A missing input +is a named fixture failure, not permission to fetch mutable data. Optional live +compatibility probes may exist only in a separate, non-authoritative workflow; +they must never contribute release JUnit, report totals, artifacts, or a +GO/NO-GO decision. + +This work must be ported to the upstream keepkey/python-keepkey repository by +reviewed PR. The fork implementation is the reference; no upstream branch was +modified while preparing it. + +## Fork reference implementation + +Branch: BitHighlander/python-keepkey:fix/hermetic-release-tests + +The implementation is intentionally isolated from the 7.14.2 Solana/TON +disclosure and PDF-report branches. Reconcile those branches only after this +one is reviewed, then repin firmware to the durable Python merge commit. + +Affected surfaces: + +- keepkeylib/tx_api.py adds configure_offline_fixtures(path), resolves a fixed + absolute fixture root, and raises OfflineFixtureError naming the complete key + instead of falling through to HTTP. +- tests/common.py makes tests/txcache module-relative and enables offline-only + mode for every KeepKeyTest. +- tests/conftest.py rejects external DNS, socket, and HTTP access per test while + permitting only loopback emulator traffic and Unix-domain sockets. +- .github/workflows/ci.yml checks fixture integrity, permits the exact local + emulator container IP, rejects every other new non-loopback connection during + authoritative pytest, and records the manifest SHA-256 in every summary. +- tests/tx_fixture_manifest.py and tests/test_tx_fixture_integrity.py account + for every fixture, reconstruct canonical transactions, recompute every txid, + test cwd independence and fail-closed misses, and statically reject new + network-capable helpers even when pytest would not collect them. +- tests/test_sign_typed_data.py and tests/test_verify_typed_data.py resolve JSON + fixtures from their module directory. +- The unused tests/zcash_rpc.py live-node helper was removed. It was not + collected by pytest, contained a fixed private-node endpoint and embedded + RPC credentials, and had no place in authoritative test infrastructure. + +## Fixture rules + +Each manifest entry records: + +- source network and transaction ID; +- response filename and SHA-256; +- raw-response filename and SHA-256 where Zcash JoinSplit reconstruction needs + it; +- canonical serialized bytes and their SHA-256; +- transaction-ID algorithm; +- every authoritative test file that references it. + +Bitcoin, Testnet, Bitcoin Gold, Dash, and pre-Overwinter Zcash transaction IDs +use double SHA-256. Groestlcoin transaction IDs use one SHA-256 round, matching +the current Groestlcoin Core HashWriter::GetHash() implementation: +https://github.com/Groestlcoin/groestlcoin/blob/master/src/hash.h + +Do not accept a fixture merely because its JSON txid field agrees with its +filename. The canonical serialization must independently hash to the same ID. + +The fork audit found and corrected one latent synthetic-fixture defect: +6e320339...a6ee37 advertised a txid computed with the null outpoint index +0xffffffff, while its decoded fixture said index 0. The corrected decoded +fixture now agrees with its canonical bytes and txid. Two cache files with no +authoritative references were removed. + +## Required upstream migration + +1. Port the fork commits without weakening the fail-closed behavior. +2. Preserve public live TxApi clients for non-test callers, but ensure + authoritative tests enable offline-only mode before constructing clients. +3. Run python tests/tx_fixture_manifest.py --check as an early CI gate. +4. Run all authoritative emulator suites with both the pytest network-denial + control and OS-level outbound-new-connection denial. +5. Treat a new transaction input as a fixture change requiring canonical-byte, + response-hash, txid, reference, and manifest review. +6. Feed the exact manifest SHA-256 into the release evidence/report pipeline. + The report job must fail if the manifest is missing, stale, mutated, or not + listed in provenance. +7. Keep optional explorer/RPC probes in a separately named workflow that + cannot satisfy or influence a required release check. Store them outside + tests/ and obtain endpoints and credentials from the workflow environment; + never commit either value. + +## Acceptance criteria + +- A clean checkout with an empty user cache runs the authoritative suite while + outbound networking is denied. +- Zero DNS, external socket, HTTP, explorer, or RPC attempt occurs. +- A missing network/txid fixture fails immediately and names the requesting + key; no HTTP fallback is possible. +- Running from the repository root and from tests/ produces identical test + counts, statuses, signed outputs, and manifest digest. +- Every fixture source is content-hashed, every canonical transaction is + retained, every txid is independently recomputed, and every fixture has at + least one authoritative test reference. +- No test is skipped or xfailed because a live service or fixture is + unavailable. +- Full Python JUnit is green before the Python commit is eligible for a + firmware submodule repin. +- The release report and provenance manifest contain the exact transaction + fixture-manifest SHA-256. + +## Upstream handback + +Return the upstream PR URL, exact head and merge commits, full offline JUnit +totals, fixture-manifest SHA-256, the network-denial result, CI run URL, and +git diff --check. Call out any historical response that cannot be reconstructed +exactly; do not silently replace, weaken, delete, or skip it. diff --git a/docs/keepkey-erc7730-v2-conformance.pdf b/docs/keepkey-erc7730-v2-conformance.pdf new file mode 100644 index 00000000..d6d47be3 Binary files /dev/null and b/docs/keepkey-erc7730-v2-conformance.pdf differ diff --git a/docs/release/CONSOLIDATION-RECEIPT-20260909.md b/docs/release/CONSOLIDATION-RECEIPT-20260909.md new file mode 100644 index 00000000..827cc724 --- /dev/null +++ b/docs/release/CONSOLIDATION-RECEIPT-20260909.md @@ -0,0 +1,135 @@ +# python-keepkey consolidation receipt — 2026-09-09 + +Single shared head for the 7.14.2 / 7.14.3 / 7.15 develop-flow release program. + +## Why + +Six python-keepkey heads were in play. The same test changes had been +cherry-picked onto several of them, and each copy was gated at whatever release +its branch was cut for — so the version gate recorded which branch a test lived +on rather than which firmware carries the fix. The report atlas +(`scripts/generate-test-report.py`), which defines what the release PDF must +contain, had forked three ways along with them. + +## Prior identities + +| Head | Pinned by | Relation to canonical `9c3982035` | +| --- | --- | --- | +| `9c3982035` | upstream fw #475/#476 | canonical (`keepkey:reconcile/upstream-sync`, PR #197 → master) | +| `7f46aa207` | fork fw `release/7.14.3-bitcoin-only` | +4, 0 behind | +| `5dae186a3` | fork fw `audit/7143-scope-repair` | +9, 0 behind | +| `08e491c60` | fork fw `release/7.15` | +8, 0 behind | +| `6268e38a3` | fork fw `audit/715-scope-repair` | +13, 0 behind | +| `d3b26aee6` | fork fw `release/7.14.2`, `audit/7142-scope-repair` | **diverged**: 66 behind / 7 ahead | +| `2ed835472` | fork fw `develop`, `alpha` | **diverged**: 50 behind / 52 ahead | + +## Assembly + +Base `5dae186a3`, merged `6268e38a3`. Merge base `7f46aa207`. Two conflicts, +one line each; nothing else conflicted. + +Duplicate pairs across the two tips: `test(reset)` dice grouping and +`test(storage)` CRC framing are byte-identical (equal patch-ids) and deduped on +merge. `test(ping)` message presence and `test(ripple)` displayed-address +differed **only** in the gate string. + +### Conflict resolutions + +Both resolved to `7.14.2`, below either side's value: + +- `tests/test_msg_ping.py::test_protected_ping_preserves_message_presence_after_debug_read` + — three copies existed, gated `7.14.2` / `7.14.3` / `7.15.0`. `fsm_msgPing` is + byte-identical between the 7.14.2 and 7.14.3 candidates, so the fix is on all + three products and the lowest gate is the correct one. +- `tests/test_msg_ripple_get_address.py` — same shape. The response-arena fix is + present in `lib/firmware/fsm_msg_ripple.h` on the 7.14.2 candidate + (`8c13ed24f`) as well. The comment claiming "older release backports are + separate" was false and was rewritten; `1ce4d3961` (7.14.3) and `885609fbe` + (7.15) reach the same end state. + +`tests/test_msg_ripple_sign_tx.py` was **not** a duplicate: `0f4c839db` asserts +memo rejection below 7.15 and self-skips above it, `fb968836b` un-skips the +THORChain memo test at 7.15.0. Complementary, auto-merged, both kept. + +## Coverage proof — nothing dropped + +Every test function on all six prior heads was diffed against the consolidated +head. Three gaps were found and each is a deliberate supersession, not a loss: + +- `d3b26aee6` EOS work: `tests/test_msg_eos_signtx.py` and + `tests/unit/test_eos_updateauth_vector.py` are **blob-identical** to the + consolidated head. Its `test_msg_signing_boundaries.py` is superseded by the + class-based rewrite, which is a strict superset (adds + `test_clear_session_aborts_every_txrequest_stage`, + `test_invalid_multisig_outputs_never_serialize_or_sign`). +- `d3b26aee6` Zcash: 6 older PCZT tests replaced on canonical's line by 12 + stricter ones, including `test_ironwood_v6_metadata_is_forwarded_exactly` + (the NU/branch-id rot fix). Consolidated blob equals canonical blob exactly. +- `test_full_715_accepts_pre_release_solana_lut_skip` was replaced by `08e491c` + with two stricter tests: `test_full_7143_accepts_unimplemented_solana_lut_skip` + and `test_full_715_requires_solana_lut_coverage`. + +`2ed835472` (fork develop/alpha) is the one head **not** covered — see exclusions. + +## Report atlas + +Single atlas at blob `b88c99396`. `MUST_RUN_MODULES['test_msg_solana_lut_attestation']` +resolves to `7.15.0`, not canonical's stale `7.16.0`: `lib/firmware/solana.c` +and `fsm_msg_solana.h` on `bd5e509cd` (7.15) carry the LUT attestation path, +while `0fe01bc1b` (7.14.3) and `8c13ed24f` (7.14.2) do not. Canonical's floor +would have let the 7.15 product silently skip its own LUT coverage. + +## Defect fixed in the same pass + +`keepkeylib/eth/ethereum_tokens.py` was fail-open. `build()` verified neither +that the vetted `ethereum-lists` source was present nor that the scan produced +anything. Measured: on a non-recursive checkout the old path yields **0 tokens +and raises nothing**, so the firmware would build green with an empty token +table and the device would show raw addresses and unknown decimals for every +ERC-20. Restored the fail-closed form already present on the fork develop line, +plus its regression test — which fails without the change (control run). + +The sibling `return` → `continue` in `add_tokens()` is corrected but is +**latent, not live**: the currently pinned `ethereum-lists` has no non-file +entries in any scanned directory, and the table is 1378 tokens either way. + +## Checks executed + +Offline suites on the consolidated head, real `ethereum-lists` checked out: + +- `tests/test_token_table_generators.py` — 5 passed, 0 skipped +- `tests/test_report_variant_validation.py` — 4 passed +- `tests/unit`, `tests/test_network_policy.py` — 4 passed, 2 subtests + (`PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python`; the local env has a + protobuf ≠ 3.20.3) +- Control: the token guard test fails without the fix, passes with it. + +Device/emulator suites were **not** run here. No firmware branch is re-pinned by +this change, so no CI was dispatched. + +## Exclusions + +- **`2ed835472` (fork develop/alpha) is not merged.** It diverges 50/52 with + zero patch-id equivalence in either direction. It carries four fail-closed + library changes and eight test functions that exist nowhere else, all + `requires_firmware("7.16.0")`-shaped: the EIP-712 `MAX_IDENTIFIER_BYTES = 31` + identifier/duplicate-member validation, the `SolanaSignTx` field-13 + `clearsign_certificate` binding, and the WETH uniswap entry. Re-pinning + develop straight to this head would silently revert them **and** delete their + guarding tests in the same change. That is its own unit. +- The report-atlas union with develop (J4 streamed-calldata commitment, section + K seed-generation hardening, `screenshot_count_audit` frame-count gate, + the GH #516 uniswap must-run entry) is deferred with it. +- `TD4` is a genuine policy contradiction, not a merge conflict: canonical has + `test_advanced_mode_gates_the_endpoint`, develop has + `test_advanced_mode_is_not_required_for_structured_review`. Needs a decision, + not a resolution. + +## Sequencing constraint + +The collapsed gates are satisfied by any firmware reporting ≥ 7.14.2, including +release branches that have **not** taken the `audit/*-scope-repair` fixes. +Against those builds these tests will fail rather than skip. That failure is +correct — they are real regressions — but the release branches must take the +audit fixes **before** any firmware branch re-pins to this head, or the +consolidation will be blamed for the red. diff --git a/keepkeylib/client.py b/keepkeylib/client.py index ddcdeffe..4cc09c64 100644 --- a/keepkeylib/client.py +++ b/keepkeylib/client.py @@ -434,13 +434,13 @@ def set_mnemonic(self, mnemonic): def call_raw(self, msg): - # Screenshot capture disabled in call_raw (captures idle screens, adds latency). - # Real confirmation screenshots are captured in callback_ButtonRequest instead. - # Exception: capture on Failure (rejection screens like invalid BIP-39 word). + # Screenshot capture is disabled in call_raw: a wire Failure is often + # emitted after the UI has already returned to the lock/home screen. + # Treating that framebuffer as operation evidence created convincing + # but unrelated blank/lock frames. Tests that claim a visible rejection + # capture it explicitly at the point the firmware renders it. resp = super(DebugLinkMixin, self).call_raw(msg) - if isinstance(resp, proto.Failure): - self._capture_oled() self._check_request(resp) return resp @@ -482,20 +482,19 @@ def reset_screenshots(self): pass self.screenshot_id = 0 - def _capture_oled(self): + def _capture_oled(self, layout=None): """Capture current OLED layout to screenshot directory.""" if not SCREENSHOT: return if not self.debug: - import sys - print("[SCREENSHOT] SKIP: no debug link", file=sys.stderr) - return + raise RuntimeError("screenshot capture requested without debug link") try: - layout = self.debug.read_layout() + if layout is None: + layout = self.debug.read_layout() if not layout or len(layout) < 1024: - import sys - print("[SCREENSHOT] SKIP: layout too small (%d bytes)" % (len(layout) if layout else 0), file=sys.stderr) - return + raise RuntimeError( + "layout too small (%d bytes)" % + (len(layout) if layout else 0)) layout_bytes = len(layout) height = 64 if layout_bytes >= 2048 else 32 rows = [] @@ -522,6 +521,66 @@ def _capture_oled(self): import sys, traceback print("[SCREENSHOT] ERROR: %s" % e, file=sys.stderr) traceback.print_exc(file=sys.stderr) + raise + + def _capture_oled_after_animation(self, seconds, required_region=None): + """Capture the completed PIN/cipher frame, not its initial blank state.""" + if not SCREENSHOT: + return + # The emulator's PIN/recovery loop blocks while waiting for host + # input. Wall-clock sleep alone therefore does not repaint: each + # DebugLink request wakes the loop for one 20 ms animation tick. + # Drive every required tick and retain the layout from the final poll. + layout = None + for _tick in range(int(seconds / 0.020) + 2): + time.sleep(0.025) + layout = self.debug.read_layout() + if required_region: + x0, x1, y0, y1 = required_region + lit = 0 + for y in range(y0, y1): + for x in range(x0, x1): + byte_index = x + (y // 8) * 256 + value = layout[byte_index] + if not isinstance(value, int): + value = ord(value) + lit += (value >> (y % 8)) & 1 + area = (x1 - x0) * (y1 - y0) + if lit < 32 or area - lit < 32: + raise RuntimeError( + "animated OLED evidence lacks grid contrast " + "(%d lit of %d pixels)" % (lit, area)) + self._capture_oled(layout) + + def _read_oled_after_settle(self): + """Return a stable confirmation frame after the render-loop handoff. + + A ButtonRequest can reach the host one or more emulator ticks before + its OLED update. Sampling immediately duplicated the preceding prompt + and omitted the security-relevant next prompt while preserving the + expected file count. DebugLink reads advance the blocked render loop; + require at least five polls and three identical final layouts. + """ + candidate = None + stable_reads = 0 + for tick in range(20): + time.sleep(0.025) + layout = self.debug.read_layout() + if layout == candidate: + stable_reads += 1 + else: + candidate = layout + stable_reads = 1 + if tick >= 4 and stable_reads >= 3: + return layout + raise RuntimeError( + 'OLED confirmation did not settle before evidence capture') + + def _capture_oled_after_settle(self): + """Capture the settled frame used for confirmation evidence.""" + if not SCREENSHOT: + return + self._capture_oled(self._read_oled_after_settle()) def capture_oled(self): """Capture a settled confirmation screen in a manual protocol flow. @@ -538,11 +597,8 @@ def callback_ButtonRequest(self, msg): if self.verbose: log("ButtonRequest code: " + get_buttonrequest_value(msg.code)) - # The firmware emits ButtonRequest immediately before drawing the - # confirmation. Allow the emulator's render transition to settle so - # regression evidence cannot capture a partially drawn OLED. - # Capture OLED screenshot BEFORE pressing button (confirmation screen) - self.capture_oled() + # Capture the completed OLED frame BEFORE pressing the button. + self._capture_oled_after_settle() if self.auto_button: if self.verbose: @@ -556,6 +612,9 @@ def callback_ButtonRequest(self, msg): return proto.ButtonAck() def callback_PinMatrixRequest(self, msg): + # Firmware animates the randomized grid for PIN_MAX_ANIMATION_MS + # (1000 ms). Sampling immediately captures only the prompt/blank mask. + self._capture_oled_after_animation(1.05, (192, 256, 0, 64)) if self.pin_correct: pin = self.debug.read_pin_encoded() else: @@ -1451,7 +1510,11 @@ def apply_policy(self, policy_name, enabled): apply_policies = proto.ApplyPolicies(policy=[policy]) out = self.call(apply_policies) - self.init_device() # Reload Features + # AdvancedMode is intentionally session-scoped on firmware 7.15+. + # Initialize is a session-boundary message, so issuing it here to + # refresh Features immediately revokes the policy this method just + # applied. Callers that explicitly need fresh Features can initialize + # after they are done with the policy-gated operation. return out @field('message') @@ -1604,6 +1667,9 @@ def sign_tx(self, coin_name, inputs, outputs, version=None, lock_time=None, debu else: msg.outputs_cnt = len(current_tx.outputs) msg.extra_data_len = len(current_tx.extra_data) if current_tx.extra_data else 0 + if debug_processor is not None: + from copy import deepcopy + msg = debug_processor(res, deepcopy(msg)) res = self.call(proto.TxAck(tx=msg)) continue @@ -1646,6 +1712,9 @@ def sign_tx(self, coin_name, inputs, outputs, version=None, lock_time=None, debu o, l = res.details.extra_data_offset, res.details.extra_data_len msg = types.TransactionType() msg.extra_data = current_tx.extra_data[o:o + l] + if debug_processor is not None: + from copy import deepcopy + msg = debug_processor(res, deepcopy(msg)) res = self.call(proto.TxAck(tx=msg)) continue @@ -2151,7 +2220,12 @@ def zcash_sign_pczt(self, address_n, actions, account=None, % (idx, n_actions)) if idx in sent_actions: raise Exception("Device requested Orchard action %d twice" % idx) - action = actions[idx] + # The public action shape mirrors ZcashPCZTAction and may therefore + # include an index. The device controls stream order, just as it + # does for transparent inputs and outputs above, so discard any + # caller copy before supplying the requested index. + action = dict(actions[idx]) + action.pop('index', None) resp = self.call(zcash_proto.ZcashPCZTAction(index=idx, **action)) sent_actions.add(idx) diff --git a/keepkeylib/erc7730.py b/keepkeylib/erc7730.py index 46c5179e..7a9e88db 100644 --- a/keepkeylib/erc7730.py +++ b/keepkeylib/erc7730.py @@ -15,6 +15,71 @@ MAX_CHUNK = 1024 MAX_RECURSION_DEPTH = 4 +MAX_PROGRAM = 16 * 1024 +MAX_PROOF_DEPTH = 16 +CERTIFICATE_LENGTH = 139 +CATALOG_DOMAIN = b"KEEPKEY:ERC7730:CATALOG\0" + + +def _catalog_leaf(program): + return hashlib.sha256(b"\x00" + program).digest() + + +def _catalog_parent(left, right): + first, second = sorted((bytes(left), bytes(right))) + if len(first) != 32 or len(second) != 32: + raise ValueError("ERC-7730 Merkle nodes must be 32 bytes") + return hashlib.sha256(b"\x01" + first + second).digest() + + +def catalog_root(program, proof=()): + """Return the sorted-pair SHA-256 root committed by a catalog proof.""" + program = bytes(program) + if len(program) < 179 or len(program) > MAX_PROGRAM: + raise ValueError("invalid ERC-7730 program length") + proof = tuple(bytes(item) for item in proof) + if len(proof) > MAX_PROOF_DEPTH: + raise ValueError("ERC-7730 proof exceeds device limit") + root = _catalog_leaf(program) + for sibling in proof: + root = _catalog_parent(root, sibling) + return root + + +def sign_envelope(program, certificate, private_key, proof=()): + """Build a K773 envelope using a KeepKey-certified delegate.""" + program = bytes(program) + certificate = bytes(certificate) + private_key = bytes(private_key) + proof = tuple(bytes(item) for item in proof) + if len(certificate) != CERTIFICATE_LENGTH: + raise ValueError("invalid KeepKey delegation certificate length") + if len(private_key) != 32: + raise ValueError("delegate private key must be 32 bytes") + if any(len(item) != 32 for item in proof): + raise ValueError("ERC-7730 proof siblings must be 32 bytes") + root = catalog_root(program, proof) + digest = hashlib.sha256(CATALOG_DOMAIN + root).digest() + try: + from ecdsa import SigningKey, SECP256k1, VerifyingKey, util + except ImportError as exc: + raise RuntimeError("The 'ecdsa' package is required to sign catalogs") from exc + key = SigningKey.from_string(private_key, curve=SECP256k1) + signature = key.sign_digest_deterministic( + digest, hashfunc=hashlib.sha256, sigencode=util.sigencode_string) + recovered = VerifyingKey.from_public_key_recovery_with_digest( + signature, digest, SECP256k1, hashfunc=hashlib.sha256) + recovery = None + for index, candidate in enumerate(recovered): + if candidate.to_string() == key.get_verifying_key().to_string(): + recovery = index + break + if recovery is None or recovery > 1: + raise RuntimeError("unable to derive canonical catalog recovery id") + return (b"K773" + bytes([1, 1]) + len(program).to_bytes(4, "big") + + program + bytes([len(proof)]) + b"".join(proof) + + len(certificate).to_bytes(2, "big") + certificate + signature + + bytes([recovery])) class Definition(object): @@ -136,4 +201,3 @@ def preload(client, definition): response.complete != (expected == len(definition.envelope))): raise RuntimeError("invalid ERC-7730 preload acknowledgement") offset = expected - diff --git a/keepkeylib/erc7730_compiler.py b/keepkeylib/erc7730_compiler.py new file mode 100644 index 00000000..08501b09 --- /dev/null +++ b/keepkeylib/erc7730_compiler.py @@ -0,0 +1,1046 @@ +"""Deterministic compiler for KeepKey's bounded ERC-7730 calldata format. + +The compiler intentionally emits the small authenticated instruction set +understood by firmware. It never decodes transaction values: paths and ABI +types are compiled here, while values are decoded again by the device. +""" + +from __future__ import absolute_import + +import hashlib +import json +import os +import re +import struct + +from .signed_metadata import keccak256 + + +ABSENT = 0xffff +HEADER_SIZE = 179 +COMPILER_ID = hashlib.sha256(b"python-keepkey:erc7730-compiler:1").digest() + + +def _merge_descriptor(base, overlay): + result = dict(base) + for key, value in overlay.items(): + if (key in result and isinstance(result[key], dict) and + isinstance(value, dict)): + result[key] = _merge_descriptor(result[key], value) + else: + result[key] = value + return result + + +def load_descriptor(path, root=None, _active=()): + """Load one descriptor and deterministically merge bounded includes.""" + path = os.path.realpath(path) + root = os.path.realpath(root or os.path.dirname(path)) + if os.path.commonpath((root, path)) != root: + raise ValueError("ERC-7730 include escapes registry root") + if path in _active: + raise ValueError("cyclic ERC-7730 include") + if len(_active) >= 16: + raise ValueError("ERC-7730 include depth exceeds limit") + with open(path, "r") as source: + descriptor = json.load(source) + includes = descriptor.pop("includes", []) + if isinstance(includes, str): + includes = [includes] + if not isinstance(includes, list): + raise ValueError("invalid ERC-7730 includes") + merged = {} + for include in includes: + if not isinstance(include, str) or not include: + raise ValueError("invalid ERC-7730 include path") + merged = _merge_descriptor( + merged, load_descriptor( + os.path.join(os.path.dirname(path), include), root, + _active + (path,))) + return _merge_descriptor(merged, descriptor) + + +def _u16(value): + if value < 0 or value > 0xffff: + raise ValueError("u16 overflow") + return struct.pack(">H", value) + + +def _u32(value): + if value < 0 or value > 0xffffffff: + raise ValueError("u32 overflow") + return struct.pack(">I", value) + + +def _u64(value): + if value < 0 or value > 0xffffffffffffffff: + raise ValueError("u64 overflow") + return struct.pack(">Q", value) + + +def _i32(value): + return struct.pack(">i", value) + + +def _hex_address(value): + if not isinstance(value, str) or not value.startswith("0x"): + raise ValueError("address must be 0x-prefixed") + raw = bytes.fromhex(value[2:]) + if len(raw) != 20: + raise ValueError("address must be 20 bytes") + return raw + + +def _unsigned_literal(value): + value = int(value) + if value < 0 or value >= (1 << 256): + raise ValueError("unsigned literal out of range") + width = max(1, (value.bit_length() + 7) // 8) + return value.to_bytes(width, "big") + + +class AbiType(object): + def __init__(self, kind, name="", size=0, children=None, + array_length=None): + self.kind = kind + self.name = name + self.size = size + self.children = list(children or ()) + self.array_length = array_length + + +class _SignatureParser(object): + _ident = re.compile(r"[A-Za-z_$][A-Za-z0-9_$]*") + + def __init__(self, text): + self.text = text + self.pos = 0 + + def _space(self): + while self.pos < len(self.text) and self.text[self.pos].isspace(): + self.pos += 1 + + def _take(self, token): + self._space() + if not self.text.startswith(token, self.pos): + raise ValueError("expected %s at %d" % (token, self.pos)) + self.pos += len(token) + + def _name(self, required=True): + self._space() + match = self._ident.match(self.text, self.pos) + if not match: + if required: + raise ValueError("expected identifier at %d" % self.pos) + return "" + self.pos = match.end() + return match.group(0) + + def type(self): + self._space() + if self.pos < len(self.text) and self.text[self.pos] == "(": + self.pos += 1 + children = [] + self._space() + if self.pos >= len(self.text) or self.text[self.pos] != ")": + while True: + child = self.type() + child.name = self._name(False) + children.append(child) + self._space() + if self.pos < len(self.text) and self.text[self.pos] == ",": + self.pos += 1 + continue + break + self._take(")") + node = AbiType(8, children=children) + else: + token = self._name() + if token.startswith("uint"): + bits = int(token[4:] or "256") + if bits < 8 or bits > 256 or bits % 8: + raise ValueError("invalid uint width") + node = AbiType(1, size=bits) + elif token.startswith("int"): + bits = int(token[3:] or "256") + if bits < 8 or bits > 256 or bits % 8: + raise ValueError("invalid int width") + node = AbiType(2, size=bits) + elif token == "address": + node = AbiType(3) + elif token == "bool": + node = AbiType(4) + elif token == "bytes": + node = AbiType(6) + elif token.startswith("bytes"): + width = int(token[5:]) + if width < 1 or width > 32: + raise ValueError("invalid bytes width") + node = AbiType(5, size=width) + elif token == "string": + node = AbiType(7) + else: + raise ValueError("unsupported ABI type %s" % token) + while True: + self._space() + if self.pos >= len(self.text) or self.text[self.pos] != "[": + break + self.pos += 1 + self._space() + start = self.pos + while self.pos < len(self.text) and self.text[self.pos].isdigit(): + self.pos += 1 + length = (ABSENT if self.pos == start + else int(self.text[start:self.pos])) + self._take("]") + node = AbiType(9, children=[node], array_length=length) + return node + + def function(self): + name = self._name() + self._take("(") + args = [] + self._space() + if self.pos >= len(self.text) or self.text[self.pos] != ")": + while True: + arg = self.type() + arg.name = self._name(False) + args.append(arg) + self._space() + if self.pos < len(self.text) and self.text[self.pos] == ",": + self.pos += 1 + continue + break + self._take(")") + self._space() + if self.pos != len(self.text): + raise ValueError("trailing function signature text") + return name, AbiType(8, children=args) + + +def parse_function_signature(signature): + return _SignatureParser(signature).function() + + +def _canonical_type(node): + names = {1: "uint%d", 2: "int%d", 3: "address", 4: "bool", + 5: "bytes%d", 6: "bytes", 7: "string"} + if node.kind == 8: + value = "(" + ",".join(_canonical_type(c) for c in node.children) + ")" + elif node.kind in (1, 2, 5): + value = names[node.kind] % node.size + elif node.kind in names: + value = names[node.kind] + elif node.kind == 9: + suffix = "" if node.array_length == ABSENT else str(node.array_length) + value = _canonical_type(node.children[0]) + "[" + suffix + "]" + else: + raise ValueError("invalid ABI kind") + return value + + +def _flatten_abi(root): + nodes = [None] + + def fill(node, index): + first = 0 + count = len(node.children) + if count: + first = len(nodes) + nodes.extend([None] * count) + nodes[index] = (node, first, count) + for offset, child in enumerate(node.children): + fill(child, first + offset) + + fill(root, 0) + if len(nodes) > 64: + raise ValueError("ABI exceeds firmware node limit") + return nodes + + +def _resolve_path(root, expression): + if not isinstance(expression, str) or not expression: + raise ValueError("invalid ERC-7730 path") + if expression == "#": + return [] + if expression.startswith("#."): + expression = expression[2:] + if expression.startswith("@."): + container = {"from": 1, "to": 2, "value": 3, "chainId": 4, + "domain": 5, "primaryType": 6} + name = expression[2:] + if name not in container: + raise ValueError("unknown container path %s" % expression) + return [("container", container[name])] + parts = expression.split(".") + node = root + steps = [] + for part in parts: + if part.startswith("[") and part.endswith("]"): + body = part[1:-1] + if body == "": + if node.kind != 9: + raise ValueError("array iteration applied to non-array") + steps.append((2,)) + node = node.children[0] + continue + if ":" in body: + start, end = body.split(":", 1) + flags = (1 if start else 0) | (2 if end else 0) + steps.append((3, flags, + int(start) if start else None, + int(end) if end else None)) + continue + if node.kind != 9: + raise ValueError("array index applied to non-array") + index = int(body) + steps.append((1, index)) + node = node.children[0] + continue + if node.kind != 8: + raise ValueError("field applied to non-tuple") + matches = [i for i, child in enumerate(node.children) + if child.name == part] + if len(matches) != 1: + raise ValueError("unknown or ambiguous path component %s" % part) + index = matches[0] + steps.append((1, index)) + node = node.children[index] + if len(steps) > 16: + raise ValueError("path exceeds firmware limit") + return steps + + +def _path_node(root, steps): + if steps and steps[0][0] == "container": + # from/to are addresses; value/chainId are unsigned integers. Domain + # and primaryType are containers and cannot be formatted as leaves. + kind = 3 if steps[0][1] in (1, 2) else 1 + return AbiType(kind) + node = root + for step in steps: + if step[0] == 1: + if node.kind == 8: + node = node.children[step[1]] + elif node.kind == 9: + node = node.children[0] + else: + raise ValueError("path continues through primitive") + elif step[0] == 2: + if node.kind != 9: + raise ValueError("iteration through non-array") + node = node.children[0] + elif step[0] == 3: + break + return node + + +def _condition_literal(node, value): + if node.kind == 1 and isinstance(value, int) and not isinstance(value, bool): + return 1, _unsigned_literal(value) + if node.kind == 2 and isinstance(value, int) and not isinstance(value, bool): + width = max(1, (value.bit_length() + 8) // 8) + return 2, value.to_bytes(width, "big", signed=True) + if node.kind == 3 and isinstance(value, str): + return 5, _hex_address(value) + if node.kind == 4 and isinstance(value, bool): + return 6, bytes([1 if value else 0]) + if node.kind in (5, 6) and isinstance(value, str) and value.startswith("0x"): + return 3, bytes.fromhex(value[2:]) + if node.kind in (5, 6) and isinstance(value, int) and value >= 0: + return 3, _unsigned_literal(value) + raise ValueError("condition value does not match ABI leaf type") + + +class CalldataCompiler(object): + """Compile one calldata format and deployment into canonical C773 bytes.""" + + FORMAT_KIND = {"raw": 1, "amount": 2, "tokenAmount": 3, + "nftName": 4, "date": 5, "duration": 6, + "unit": 7, "enum": 8, "chainId": 9, + "addressName": 10, "tokenTicker": 11, + "interoperableAddress": 12, "calldata": 13, + "encrypted": 14} + + def __init__(self, descriptor, signature, chain_id, address, + provider_id=1, issuance_epoch=0, revocation_epoch=0, + token_records=(), network_records=(), definition_kind=1, + primary_type_hash=None, domain_constraints=()): + self.descriptor = descriptor + self.signature = signature + self.chain_id = int(chain_id) + self.address = _hex_address(address) if isinstance(address, str) else bytes(address) + if len(self.address) != 20: + raise ValueError("contract address must be 20 bytes") + self.provider_id = provider_id + self.issuance_epoch = issuance_epoch + self.revocation_epoch = revocation_epoch + self.token_records = list(token_records) + self.network_records = list(network_records) + self.definition_kind = definition_kind + self.primary_type_hash = primary_type_hash + self.domain_constraints = list(domain_constraints) + if definition_kind not in (1, 2): + raise ValueError("compiler supports calldata or EIP-712 programs") + if definition_kind == 2 and (primary_type_hash is None or + len(primary_type_hash) != 32): + raise ValueError("EIP-712 requires a primary type hash") + + def compile(self): + function_name, root = parse_function_signature(self.signature) + canonical_signature = function_name + "(" + ",".join( + _canonical_type(c) for c in root.children) + ")" + formats = self.descriptor.get("display", {}).get("formats", {}) + selected = formats.get(self.signature) + if selected is None: + for candidate, value in formats.items(): + parsed_name, parsed_root = parse_function_signature(candidate) + candidate_canonical = parsed_name + "(" + ",".join( + _canonical_type(c) for c in parsed_root.children) + ")" + if candidate_canonical == canonical_signature: + selected = value + break + if selected is None: + raise KeyError("signature is not described") + + def descriptor_value(reference): + if not isinstance(reference, str) or not reference.startswith("$."): + return reference + value = self.descriptor + for component in reference[2:].split("."): + if not isinstance(value, dict) or component not in value: + raise ValueError("unresolved descriptor value %s" % reference) + value = value[component] + return value + + def normalized_path(path): + return path[2:] if isinstance(path, str) and path.startswith("#.") else path + + def resolve_field(field): + reference = field.get("$ref") + if not reference: + return dict(field) + prefix = "$.display.definitions." + if not reference.startswith(prefix): + raise ValueError("unsupported field reference") + name = reference[len(prefix):] + base = self.descriptor.get("display", {}).get( + "definitions", {}).get(name) + if not isinstance(base, dict): + raise ValueError("unresolved field reference") + result = dict(base) + result.update((key, value) for key, value in field.items() + if key != "$ref" and key != "params") + params = dict(base.get("params", {})) + params.update(field.get("params", {})) + if params: + result["params"] = params + return result + + field_specs = [] + group_ranges = [] + + def join_path(prefix, path): + if not prefix or (isinstance(path, str) and + path.startswith(("#.", "@.", "$."))): + return path + if not path: + return prefix + return prefix + "." + path + + def flatten_fields(items, prefix=None): + for item in items: + if "fields" not in item: + field = dict(item) + if "path" in field: + field["path"] = join_path(prefix, field["path"]) + if prefix: + field["_path_prefix"] = prefix + field_specs.append(field) + continue + group_path = join_path(prefix, item.get("path")) + start = len(field_specs) + flatten_fields(item.get("fields", ()), group_path) + end = len(field_specs) + if end == start: + raise ValueError("display group must contain a field") + group_ranges.append((start, end, item.get("label"), group_path)) + + flatten_fields(selected.get("fields", [])) + + strings = set([selected.get("intent", selected.get("$id", function_name))]) + for unused_start, unused_end, group_label, unused_path in group_ranges: + if group_label: + strings.add(group_label) + interpolation = selected.get("interpolatedIntent") + interpolation_tokens = [] + interpolation_values = set() + if interpolation is not None: + cursor = 0 + for match in re.finditer(r"\{([^{}]+)\}", interpolation): + if match.start() > cursor: + text = interpolation[cursor:match.start()] + strings.add(text) + interpolation_tokens.append(("text", text)) + interpolation_tokens.append(("value", match.group(1))) + interpolation_values.add(normalized_path(match.group(1))) + cursor = match.end() + if cursor < len(interpolation): + text = interpolation[cursor:] + strings.add(text) + interpolation_tokens.append(("text", text)) + for record in self.token_records: + strings.add(record[2]) + for record in self.network_records: + strings.add(record[1]) + strings.add(record[2]) + for field, value in self.domain_constraints: + if field in (1, 2): + strings.add(value) + fields = [] + for unresolved in field_specs: + field = resolve_field(unresolved) + if field.get("visible") == "never": + if normalized_path(field.get("path")) in interpolation_values: + # The compiled protocol requires every interpolated value + # to remain independently reviewable as an unconditional + # field. Promote registry shorthand that marks the source + # field hidden rather than weakening atomic interpolation. + field["visible"] = "always" + else: + continue + label = field.get("label") + path = field.get("path") + constant_value = (descriptor_value(field.get("value")) + if "value" in field else None) + kind_name = field.get("format", "raw") + if (not label or (not path and "value" not in field) or + kind_name not in self.FORMAT_KIND): + raise ValueError("invalid display field") + strings.add(label) + if isinstance(constant_value, str) and not constant_value.startswith("0x"): + strings.add(constant_value) + params = field.get("params", {}) + prefix = field.get("_path_prefix") + if prefix: + params = dict(params) + for key in ("tokenPath", "collectionPath", "chainIdPath", + "calleePath", "selectorPath", "amountPath", + "spenderPath"): + if key in params: + params[key] = join_path(prefix, params[key]) + field["params"] = params + if kind_name == "enum": + enum_ref = params.get("$ref") + prefix = "$.metadata.enums." + if not isinstance(enum_ref, str) or not enum_ref.startswith(prefix): + raise ValueError("enum requires a metadata enum reference") + enum_values = self.descriptor.get("metadata", {}).get( + "enums", {}).get(enum_ref[len(prefix):]) + if not isinstance(enum_values, dict) or not enum_values: + raise ValueError("unresolved enum reference") + for enum_label in enum_values.values(): + strings.add(enum_label) + if kind_name == "date": + strings.add(params.get("encoding", "timestamp")) + elif kind_name == "unit": + base = params.get("base") + if not isinstance(base, str) or not base: + raise ValueError("unit requires base") + strings.add(base) + elif kind_name == "tokenAmount" and params.get("message"): + strings.add(params["message"]) + separator = field.get("separator") + if separator: + strings.add(separator) + fields.append((field, (("constant", constant_value),) + if "value" in field else _resolve_path(root, path))) + strings = sorted(s.encode("utf-8") for s in strings) + if any(not value or len(value) > 128 for value in strings): + raise ValueError("invalid string length") + string_index = dict((value.decode("utf-8"), i) + for i, value in enumerate(strings)) + + paths = [] + path_index = {} + def intern_path(steps): + key = tuple(steps) + if key not in path_index: + path_index[key] = len(paths) + paths.append(steps) + return path_index[key] + + literals = [] + formatters = [] + conditions = [] + optional_condition = None + displays = [[1, string_index[selected.get("intent", selected.get("$id", function_name))], ABSENT, ABSENT]] + if interpolation_tokens: + formatter_by_path = {} + for index, (field, unused_steps) in enumerate(fields): + if field.get("visible", "always") == "always": + formatter_by_path[normalized_path(field.get("path"))] = index + for token_kind, token_value in interpolation_tokens: + if token_kind == "text": + displays.append([2, string_index[token_value], ABSENT, ABSENT]) + else: + token_value = normalized_path(token_value) + if token_value not in formatter_by_path: + raise ValueError( + "interpolated value must reference an always-visible field") + displays.append([3, formatter_by_path[token_value], ABSENT, ABSENT]) + + domain_records = [] + for field, value in self.domain_constraints: + if field in (1, 2): + literal = (4, _u16(string_index[value])) + elif field == 3: + literal = (7, _unsigned_literal(value)) + elif field == 4: + literal = (5, _hex_address(value) if isinstance(value, str) + else bytes(value)) + elif field == 5: + literal = (3, bytes.fromhex(value[2:]) + if isinstance(value, str) and value.startswith("0x") + else bytes(value)) + else: + raise ValueError("unknown EIP-712 domain field") + literals.append(literal) + domain_records.append((2, bytes([field, 1]) + + _u16(len(literals) - 1))) + groups_starting = {} + groups_ending = {} + for start, end, label, group_path in group_ranges: + groups_starting.setdefault(start, []).append((end, label, group_path)) + groups_ending.setdefault(end, []).append((start, label, group_path)) + active_group_pcs = [] + + for field_number, (field, steps) in enumerate(fields): + controlled_arrays = 0 + for unused_end, label, group_path in sorted( + groups_starting.get(field_number, ()), reverse=True): + array_pc = None + if group_path and ".[]" in group_path: + array_steps = _resolve_path(root, group_path) + array_pc = len(displays) + displays.append([7, intern_path(array_steps), ABSENT, 0]) + controlled_arrays += sum( + 1 for step in array_steps if step[0] == 2) + begin_pc = len(displays) + displays.append([5, string_index[label] if label else ABSENT, + ABSENT, 0]) + active_group_pcs.append((begin_pc, array_pc)) + for start, end, unused_label, group_path in group_ranges: + if start < field_number < end and group_path and ".[]" in group_path: + controlled_arrays += group_path.split(".").count("[]") + if steps and steps[0][0] == "constant": + value = descriptor_value(steps[0][1]) + if isinstance(value, bool): + literal = (6, bytes([1 if value else 0])) + elif isinstance(value, int): + literal = (1, _unsigned_literal(value)) + elif isinstance(value, str) and value.startswith("0x"): + raw = bytes.fromhex(value[2:]) + literal = (5 if len(raw) == 20 else 3, raw) + elif isinstance(value, str): + literal = (4, _u16(string_index[value])) + else: + raise ValueError("unsupported constant display value") + literals.append(literal) + steps = (("literal", len(literals) - 1),) + value_path = intern_path(steps) + kind = self.FORMAT_KIND[field.get("format", "raw")] + arguments = [(1, 1, value_path)] + params = field.get("params", {}) + if kind == 3: + token = params.get("tokenPath") + if token is None: + token = params.get("token") + token = descriptor_value(token) + if isinstance(token, str) and token.startswith("0x"): + raw = _hex_address(token) + literals.append((5, raw)) + literal_path = intern_path((("literal", len(literals) - 1),)) + arguments.append((2, 1, literal_path)) + elif isinstance(token, str): + arguments.append((2, 1, intern_path(_resolve_path(root, token)))) + elif token is not None: + raise ValueError("tokenAmount requires token or tokenPath") + elif any(key in params for key in ( + "threshold", "message", "chainId", "chainIdPath")): + raise ValueError( + "unknown token amount cannot use token metadata parameters") + if "threshold" in params: + threshold = descriptor_value(params["threshold"]) + if isinstance(threshold, str) and threshold.startswith("0x"): + threshold = int(threshold, 16) + literals.append((1, _unsigned_literal(threshold))) + arguments.append((7, 2, len(literals) - 1)) + if params.get("message"): + arguments.append((8, 3, string_index[params["message"]])) + if "chainId" in params: + chain = params["chainId"] + if isinstance(chain, int): + literals.append((7, _unsigned_literal(chain))) + arguments.append((11, 2, len(literals) - 1)) + elif isinstance(chain, str): + arguments.append((11, 1, + intern_path(_resolve_path(root, chain)))) + else: + raise ValueError("invalid tokenAmount chainId") + aliases = params.get("nativeCurrencyAddress", ()) + aliases = descriptor_value(aliases) + if aliases and token is not None: + if isinstance(aliases, str): + aliases = [aliases] + references = [] + for alias in aliases: + alias = descriptor_value(alias) + literals.append((5, _hex_address(alias))) + references.append(len(literals) - 1) + literals.append((9, _u16(len(references)) + b"".join( + _u16(index) for index in references))) + arguments.append((22, 2, len(literals) - 1)) + elif kind == 4: + collection = params.get("collectionPath") + if collection is None: + collection = params.get("collection") + collection = descriptor_value(collection) + if isinstance(collection, str) and collection.startswith("0x"): + literals.append((5, _hex_address(collection))) + collection_path = intern_path( + (("literal", len(literals) - 1),)) + elif isinstance(collection, str): + collection_path = intern_path(_resolve_path(root, collection)) + else: + raise ValueError("nftName requires collection or collectionPath") + arguments.append((3, 1, collection_path)) + chain = params.get("chainIdPath", params.get("chainId")) + if chain is not None: + chain = descriptor_value(chain) + if isinstance(chain, int): + literals.append((7, _unsigned_literal(chain))) + arguments.append((11, 2, len(literals) - 1)) + elif isinstance(chain, str): + arguments.append((11, 1, + intern_path(_resolve_path(root, chain)))) + else: + raise ValueError("invalid nftName chainId") + elif kind == 5: + encoding = params.get("encoding", "timestamp") + arguments.append((9, 3, string_index[encoding])) + elif kind == 7: + decimals = params.get("decimals", 0) + literals.append((1, _unsigned_literal(decimals))) + arguments.append((4, 2, len(literals) - 1)) + arguments.append((5, 3, string_index[params["base"]])) + literals.append((6, bytes([1 if params.get("prefix") else 0]))) + arguments.append((6, 2, len(literals) - 1)) + elif kind == 8: + enum_ref = params["$ref"] + enum_values = self.descriptor["metadata"]["enums"][ + enum_ref[len("$.metadata.enums."):]] + node = _path_node(root, steps) + pairs = [] + for raw_key, label in sorted(enum_values.items()): + if node.kind == 4: + bool_key = raw_key.lower() + if bool_key not in ("true", "false", "1", "0"): + raise ValueError("boolean enum key must be true or false") + key = bool_key in ("true", "1") + elif node.kind in (1, 2): + key = int(raw_key, 0) + elif node.kind == 3: + key = raw_key + elif node.kind in (5, 6): + key = (raw_key if raw_key.startswith("0x") + else int(raw_key, 0)) + else: + raise ValueError("enum requires a scalar ABI value") + literals.append(_condition_literal(node, key)) + pairs.append((len(literals) - 1, string_index[label])) + pairs.sort() + literals.append((8, _u16(len(pairs)) + b"".join( + _u16(key) + _u16(value) for key, value in pairs))) + arguments.append((10, 2, len(literals) - 1)) + elif kind == 13: + callee = params.get("calleePath") + if not callee: + raise ValueError("embedded calldata requires calleePath") + arguments.append((15, 1, intern_path(_resolve_path(root, callee)))) + formatter_index = len(formatters) + formatters.append((kind, arguments)) + condition = ABSENT + visibility = field.get("visible") + if visibility == "optional": + if optional_condition is None: + optional_condition = len(conditions) + conditions.append((3, ABSENT, ABSENT)) + condition = optional_condition + elif isinstance(visibility, dict): + keys = [key for key in ("ifNotIn", "mustMatch") + if key in visibility] + if len(keys) != 1 or not visibility[keys[0]]: + raise ValueError("invalid visibility rule") + references = [] + node = _path_node(root, steps) + for value in visibility[keys[0]]: + literal = _condition_literal(node, value) + literals.append(literal) + references.append(len(literals) - 1) + set_value = _u16(len(references)) + b"".join( + _u16(index) for index in references) + literals.append((9, set_value)) + condition = len(conditions) + conditions.append((7 if keys[0] == "ifNotIn" else 8, + value_path, len(literals) - 1)) + all_positions = [i for i, step in enumerate(steps) + if step[0] == 2] + all_positions = all_positions[controlled_arrays:] + if all_positions: + begins = [] + for position in all_positions: + array_path = intern_path(steps[:position + 1]) + begin = len(displays) + begins.append(begin) + displays.append([7, array_path, condition, 0]) + displays.append([4, string_index[field["label"]], + formatter_index, ABSENT]) + separator = field.get("separator") + for depth, begin in enumerate(reversed(begins)): + end = len(displays) + displays.append([ + 8, begin, + (string_index[separator] + if separator and depth == len(begins) - 1 else ABSENT), + ABSENT]) + displays[begin][3] = end + else: + displays.append([4, string_index[field["label"]], + formatter_index, condition]) + for unused_start, unused_label, unused_path in reversed( + groups_ending.get(field_number + 1, ())): + if not active_group_pcs: + raise ValueError("unbalanced display group") + begin_pc, array_pc = active_group_pcs.pop() + end_pc = len(displays) + displays.append([6, begin_pc, ABSENT, ABSENT]) + displays[begin_pc][3] = end_pc + if array_pc is not None: + array_end = len(displays) + displays.append([8, array_pc, ABSENT, ABSENT]) + displays[array_pc][3] = array_end + if active_group_pcs: + raise ValueError("unbalanced display group") + displays.append([10, ABSENT, ABSENT, ABSENT]) + + if (len(paths) > 64 or len(formatters) > 64 or len(displays) > 64 or + len(conditions) > 32): + raise ValueError("compiled program exceeds table limits") + + sections = [] + payload = _u16(len(strings)) + b"".join(_u16(len(s)) + s for s in strings) + sections.append((1, payload)) + flat = _flatten_abi(root) + payload = _u16(len(flat)) + def depth(node): + return 1 + (max(depth(child) for child in node.children) + if node.children else 0) + max_depth = depth(root) + for node, first, count in flat: + array_length = node.array_length if node.kind == 9 else 0 + payload += bytes([node.kind]) + _u16(node.size) + _u16(first) + _u16(count) + _u16(array_length or 0) + sections.append((2, payload)) + payload = _u16(len(paths)) + for steps in paths: + if steps and steps[0][0] == "literal": + payload += bytes([3, 0]) + _u16(steps[0][1]) + continue + if steps and steps[0][0] == "container": + payload += bytes([2, 0]) + _u16(steps[0][1]) + continue + payload += bytes([1, len(steps)]) + _u16(ABSENT) + for step in steps: + if step[0] == 1: + payload += bytes([1]) + _i32(step[1]) + elif step[0] == 2: + payload += bytes([2]) + else: + payload += bytes([3, step[1]]) + if step[1] & 1: + payload += _i32(step[2]) + if step[1] & 2: + payload += _i32(step[3]) + sections.append((3, payload)) + if literals: + payload = _u16(len(literals)) + b"".join( + bytes([kind]) + _u16(len(value)) + value + for kind, value in literals) + sections.append((4, payload)) + if conditions: + payload = _u16(len(conditions)) + b"".join( + bytes([opcode]) + _u16(path) + _u16(literal_set) + + bytes([0]) + _u16(0) + for opcode, path, literal_set in conditions) + sections.append((5, payload)) + payload = _u16(len(formatters)) + for kind, arguments in formatters: + payload += bytes([kind, 0, len(arguments)]) + for role, source, index in sorted(arguments): + payload += bytes([role, source]) + _u16(index) + sections.append((6, payload)) + payload = _u16(len(displays)) + b"".join( + bytes([op, 0]) + _u16(a) + _u16(b) + _u16(c) + for op, a, b, c in displays) + sections.append((7, payload)) + bindings = [(1, _u64(self.chain_id) + self.address)] + domain_records + for record in self.token_records: + ticker = record[2] + if ticker not in string_index: + raise ValueError("token ticker must be used by display strings") + bindings.append((3, _u64(record[0]) + _hex_address(record[1]) + + _u16(string_index[ticker]) + bytes([record[3]]))) + for record in self.network_records: + bindings.append((4, _u64(record[0]) + + _u16(string_index[record[1]]) + + _u16(string_index[record[2]]) + + bytes([record[3]]))) + bindings.sort(key=lambda item: (item[0], item[1])) + payload = _u16(len(bindings)) + b"".join( + bytes([kind]) + _u16(len(value)) + value for kind, value in bindings) + sections.append((8, payload)) + display_depth = 0 + display_max_depth = 0 + for instruction in displays: + if instruction[0] in (5, 7): + display_depth += 1 + display_max_depth = max(display_max_depth, display_depth) + elif instruction[0] in (6, 8): + display_depth -= 1 + if display_depth != 0: + raise ValueError("unbalanced display program") + resource = [_u16(len(strings)), _u16(len(flat)), _u16(len(paths)), + _u16(len(literals)), _u16(len(conditions)), _u16(len(formatters)), + _u16(len(displays)), _u16(len(bindings)), + bytes([max_depth, + 64 if any(step[0] == 2 for path in paths + for step in path) else 0, + display_max_depth, + 1 if any(kind == 13 for kind, _ in formatters) else 0]), + _u16(max([len(s) for s in strings] or [0]))] + sections.append((9, b"".join(resource))) + + source = json.dumps(self.descriptor, sort_keys=True, + separators=(",", ":")).encode("utf-8") + token_hash = hashlib.sha256(b"".join(value for _, value in bindings + if _ != 1)).digest() + selector = (keccak256(canonical_signature.encode("ascii"))[:4] + bytes(28) + if self.definition_kind == 1 else self.primary_type_hash) + header = (b"C773" + bytes([1, 2, 0, self.definition_kind]) + _u16(0) + + _u64(self.chain_id) + self.address + selector + + hashlib.sha256(source).digest() + COMPILER_ID + token_hash + + _u32(self.provider_id) + _u32(self.issuance_epoch) + + _u32(self.revocation_epoch) + bytes([len(sections)])) + if len(header) != HEADER_SIZE: + raise AssertionError("invalid C773 header size") + return header + b"".join(bytes([kind]) + _u32(len(value)) + value + for kind, value in sections) + + +def compile_calldata(descriptor, signature, chain_id, address, **kwargs): + return CalldataCompiler(descriptor, signature, chain_id, address, + **kwargs).compile() + + +def _typed_base(type_name, types, active): + array = re.match(r"^(.*)\[([0-9]*)\]$", type_name) + if array: + child = _typed_base(array.group(1), types, active) + length = ABSENT if array.group(2) == "" else int(array.group(2)) + return AbiType(9, children=[child], array_length=length) + if type_name in types: + if type_name in active: + raise ValueError("recursive EIP-712 type") + children = [] + for member in types[type_name]: + child = _typed_base(member["type"], types, active | {type_name}) + child.name = member["name"] + children.append(child) + return AbiType(8, children=children) + parser = _SignatureParser(type_name) + node = parser.type() + parser._space() + if parser.pos != len(type_name): + raise ValueError("invalid EIP-712 member type") + return node + + +def eip712_encode_type(primary_type, types): + if primary_type not in types: + raise ValueError("missing EIP-712 primary type") + dependencies = set() + + def visit(name): + for member in types[name]: + base = re.sub(r"\[[0-9]*\]$", "", member["type"]) + if base in types and base != primary_type and base not in dependencies: + dependencies.add(base) + visit(base) + + visit(primary_type) + def declaration(name): + return name + "(" + ",".join( + member["type"] + " " + member["name"] + for member in types[name]) + ")" + return declaration(primary_type) + "".join( + declaration(name) for name in sorted(dependencies)) + + +def compile_eip712(descriptor, typed_data, chain_id=None, address=None, + **kwargs): + """Compile one EIP-712 descriptor against its exact typed-data schema.""" + types = typed_data["types"] + primary = typed_data["primaryType"] + root = _typed_base(primary, types, set()) + def named(node): + if node.kind == 8: + value = "(" + ",".join( + named(child) + (" " + child.name if child.name else "") + for child in node.children) + ")" + elif node.kind == 9: + suffix = "" if node.array_length == ABSENT else str(node.array_length) + value = named(node.children[0]) + "[" + suffix + "]" + else: + value = _canonical_type(node) + return value + signature = primary + "(" + ",".join( + named(child) + (" " + child.name if child.name else "") + for child in root.children) + ")" + formats = descriptor.get("display", {}).get("formats", {}) + selected = None + for key, value in formats.items(): + if key.startswith(primary + "("): + selected = value + break + if selected is None: + raise KeyError("primary type is not described") + synthetic = dict(descriptor) + synthetic["display"] = dict(descriptor.get("display", {})) + synthetic["display"]["formats"] = {signature: selected} + domain = typed_data.get("domain", {}) + if chain_id is None: + chain_id = domain.get("chainId") + if address is None: + address = domain.get("verifyingContract") + if not chain_id or not address: + raise ValueError("EIP-712 chain and verifying contract are required") + constraints = [] + for name, field in (("name", 1), ("version", 2), ("chainId", 3), + ("verifyingContract", 4), ("salt", 5)): + if name in domain: + constraints.append((field, domain[name])) + type_hash = keccak256(eip712_encode_type(primary, types).encode("ascii")) + return CalldataCompiler( + synthetic, signature, chain_id, address, definition_kind=2, + primary_type_hash=type_hash, domain_constraints=constraints, + **kwargs).compile() diff --git a/keepkeylib/messages_ethereum_pb2.py b/keepkeylib/messages_ethereum_pb2.py index fde04ada..06c6e087 100644 --- a/keepkeylib/messages_ethereum_pb2.py +++ b/keepkeylib/messages_ethereum_pb2.py @@ -1,11 +1,14 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: messages-ethereum.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool +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() @@ -14,66 +17,1559 @@ from . import types_pb2 as types__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17messages-ethereum.proto\x1a\x0btypes.proto\"=\n\x12\x45thereumGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\"7\n\x0f\x45thereumAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\x0c\x12\x13\n\x0b\x61\x64\x64ress_str\x18\x02 \x01(\t\"\x95\x03\n\x0e\x45thereumSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x11\n\tgas_price\x18\x03 \x01(\x0c\x12\x11\n\tgas_limit\x18\x04 \x01(\x0c\x12\n\n\x02to\x18\x05 \x01(\x0c\x12\r\n\x05value\x18\x06 \x01(\x0c\x12\x1a\n\x12\x64\x61ta_initial_chunk\x18\x07 \x01(\x0c\x12\x13\n\x0b\x64\x61ta_length\x18\x08 \x01(\r\x12\x14\n\x0cto_address_n\x18\t \x03(\r\x12(\n\x0c\x61\x64\x64ress_type\x18\n \x01(\x0e\x32\x12.OutputAddressType\x12\x10\n\x08\x63hain_id\x18\x0c \x01(\r\x12\x17\n\x0fmax_fee_per_gas\x18\r \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x0e \x01(\x0c\x12\x13\n\x0btoken_value\x18\x64 \x01(\x0c\x12\x10\n\x08token_to\x18\x65 \x01(\x0c\x12\x16\n\x0etoken_shortcut\x18\x66 \x01(\t\x12\x0f\n\x07tx_type\x18g \x01(\r\x12\x0c\n\x04type\x18h \x01(\rJ\x04\x08\x0b\x10\x0c\"\x8c\x01\n\x11\x45thereumTxRequest\x12\x13\n\x0b\x64\x61ta_length\x18\x01 \x01(\r\x12\x13\n\x0bsignature_v\x18\x02 \x01(\r\x12\x13\n\x0bsignature_r\x18\x03 \x01(\x0c\x12\x13\n\x0bsignature_s\x18\x04 \x01(\x0c\x12\x0c\n\x04hash\x18\x05 \x01(\x0c\x12\x15\n\rsignature_der\x18\x06 \x01(\x0c\"#\n\rEthereumTxAck\x12\x12\n\ndata_chunk\x18\x01 \x01(\x0c\"V\n\x12\x45thereumTxMetadata\x12\x16\n\x0esigned_payload\x18\x01 \x01(\x0c\x12\x18\n\x10metadata_version\x18\x02 \x01(\r\x12\x0e\n\x06key_id\x18\x03 \x01(\r\"F\n\x13\x45thereumMetadataAck\x12\x16\n\x0e\x63lassification\x18\x01 \x02(\r\x12\x17\n\x0f\x64isplay_summary\x18\x02 \x01(\t\"\x8c\x01\n\x13LoadClearsignSigner\x12\x0e\n\x06key_id\x18\x01 \x01(\r\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\x0c\n\x04icon\x18\x04 \x01(\x0c\x12\x12\n\nicon_width\x18\x05 \x01(\r\x12\x13\n\x0bicon_height\x18\x06 \x01(\r\x12\x0f\n\x07persist\x18\x07 \x01(\x08\"9\n\x13\x45thereumSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\"L\n\x15\x45thereumVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\">\n\x18\x45thereumMessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"_\n\x15\x45thereumSignTypedHash\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1d\n\x15\x64omain_separator_hash\x18\x02 \x02(\x0c\x12\x14\n\x0cmessage_hash\x18\x03 \x01(\x0c\"\x8b\x01\n\x1a\x45thereumTypedDataSignature\x12\x11\n\tsignature\x18\x01 \x02(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x02(\t\x12\x1d\n\x15\x64omain_separator_hash\x18\x03 \x01(\x0c\x12\x14\n\x0chas_msg_hash\x18\x04 \x02(\x08\x12\x14\n\x0cmessage_hash\x18\x05 \x01(\x0c\"\x85\x01\n\x16\x45thereum712TypesValues\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x13\n\x0b\x65ip712types\x18\x02 \x02(\t\x12\x17\n\x0f\x65ip712primetype\x18\x03 \x02(\t\x12\x12\n\neip712data\x18\x04 \x02(\t\x12\x16\n\x0e\x65ip712typevals\x18\x05 \x02(\r\"b\n\x15\x45thereumSignTypedData\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cprimary_type\x18\x02 \x02(\t\x12 \n\x12metamask_v4_compat\x18\x03 \x01(\x08:\x04true\".\n\x1e\x45thereumTypedDataStructRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\"\xbe\x03\n\x1a\x45thereumTypedDataStructAck\x12\x41\n\x07members\x18\x01 \x03(\x0b\x32\x30.EthereumTypedDataStructAck.EthereumStructMember\x1a\x61\n\x14\x45thereumStructMember\x12;\n\x04type\x18\x01 \x02(\x0b\x32-.EthereumTypedDataStructAck.EthereumFieldType\x12\x0c\n\x04name\x18\x02 \x02(\t\x1a\x8d\x01\n\x11\x45thereumFieldType\x12?\n\tdata_type\x18\x01 \x02(\x0e\x32,.EthereumTypedDataStructAck.EthereumDataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12\x14\n\x0c\x61rray_levels\x18\x04 \x03(\r\"j\n\x10\x45thereumDataType\x12\x08\n\x04UINT\x10\x01\x12\x07\n\x03INT\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06STRING\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x0b\n\x07\x41\x44\x44RESS\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"4\n\x1d\x45thereumTypedDataValueRequest\x12\x13\n\x0bmember_path\x18\x01 \x03(\r\"*\n\x19\x45thereumTypedDataValueAck\x12\r\n\x05value\x18\x01 \x02(\x0c\"h\n\x1b\x45thereumClearSignDefinition\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c\"^\n\x1e\x45thereumClearSignDefinitionAck\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x13\n\x0bnext_offset\x18\x02 \x02(\r\x12\x10\n\x08\x63omplete\x18\x03 \x02(\x08\"\xef\x01\n\"EthereumClearSignDefinitionRequest\x12.\n\x04kind\x18\x01 \x02(\x0e\x32 .EthereumClearSignDefinitionKind\x12\x10\n\x08\x63hain_id\x18\x02 \x02(\x04\x12\x18\n\x10\x63ontract_address\x18\x03 \x01(\x0c\x12\x1d\n\x15selector_or_type_hash\x18\x04 \x01(\x0c\x12\x15\n\rdefinition_id\x18\x05 \x01(\x0c\x12\x0e\n\x06offset\x18\x06 \x02(\r\x12\x0e\n\x06length\x18\x07 \x02(\r\x12\x17\n\x0frecursion_depth\x18\x08 \x01(\r\"m\n EthereumClearSignDefinitionChunk\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c*s\n\x1f\x45thereumClearSignDefinitionKind\x12\x14\n\x10\x45RC7730_CALLDATA\x10\x01\x12\x12\n\x0e\x45RC7730_EIP712\x10\x02\x12\x11\n\rERC7730_TOKEN\x10\x03\x12\x13\n\x0f\x45RC7730_NETWORK\x10\x04\x42\x34\n\x1a\x63om.keepkey.deviceprotocolB\x16KeepKeyMessageEthereum') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'messages_ethereum_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\032com.keepkey.deviceprotocolB\026KeepKeyMessageEthereum' - _ETHEREUMCLEARSIGNDEFINITIONKIND._serialized_start=2877 - _ETHEREUMCLEARSIGNDEFINITIONKIND._serialized_end=2992 - _ETHEREUMGETADDRESS._serialized_start=40 - _ETHEREUMGETADDRESS._serialized_end=101 - _ETHEREUMADDRESS._serialized_start=103 - _ETHEREUMADDRESS._serialized_end=158 - _ETHEREUMSIGNTX._serialized_start=161 - _ETHEREUMSIGNTX._serialized_end=566 - _ETHEREUMTXREQUEST._serialized_start=569 - _ETHEREUMTXREQUEST._serialized_end=709 - _ETHEREUMTXACK._serialized_start=711 - _ETHEREUMTXACK._serialized_end=746 - _ETHEREUMTXMETADATA._serialized_start=748 - _ETHEREUMTXMETADATA._serialized_end=834 - _ETHEREUMMETADATAACK._serialized_start=836 - _ETHEREUMMETADATAACK._serialized_end=906 - _LOADCLEARSIGNSIGNER._serialized_start=909 - _LOADCLEARSIGNSIGNER._serialized_end=1049 - _ETHEREUMSIGNMESSAGE._serialized_start=1051 - _ETHEREUMSIGNMESSAGE._serialized_end=1108 - _ETHEREUMVERIFYMESSAGE._serialized_start=1110 - _ETHEREUMVERIFYMESSAGE._serialized_end=1186 - _ETHEREUMMESSAGESIGNATURE._serialized_start=1188 - _ETHEREUMMESSAGESIGNATURE._serialized_end=1250 - _ETHEREUMSIGNTYPEDHASH._serialized_start=1252 - _ETHEREUMSIGNTYPEDHASH._serialized_end=1347 - _ETHEREUMTYPEDDATASIGNATURE._serialized_start=1350 - _ETHEREUMTYPEDDATASIGNATURE._serialized_end=1489 - _ETHEREUM712TYPESVALUES._serialized_start=1492 - _ETHEREUM712TYPESVALUES._serialized_end=1625 - _ETHEREUMSIGNTYPEDDATA._serialized_start=1627 - _ETHEREUMSIGNTYPEDDATA._serialized_end=1725 - _ETHEREUMTYPEDDATASTRUCTREQUEST._serialized_start=1727 - _ETHEREUMTYPEDDATASTRUCTREQUEST._serialized_end=1773 - _ETHEREUMTYPEDDATASTRUCTACK._serialized_start=1776 - _ETHEREUMTYPEDDATASTRUCTACK._serialized_end=2222 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER._serialized_start=1873 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER._serialized_end=1970 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE._serialized_start=1973 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE._serialized_end=2114 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE._serialized_start=2116 - _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE._serialized_end=2222 - _ETHEREUMTYPEDDATAVALUEREQUEST._serialized_start=2224 - _ETHEREUMTYPEDDATAVALUEREQUEST._serialized_end=2276 - _ETHEREUMTYPEDDATAVALUEACK._serialized_start=2278 - _ETHEREUMTYPEDDATAVALUEACK._serialized_end=2320 - _ETHEREUMCLEARSIGNDEFINITION._serialized_start=2322 - _ETHEREUMCLEARSIGNDEFINITION._serialized_end=2426 - _ETHEREUMCLEARSIGNDEFINITIONACK._serialized_start=2428 - _ETHEREUMCLEARSIGNDEFINITIONACK._serialized_end=2522 - _ETHEREUMCLEARSIGNDEFINITIONREQUEST._serialized_start=2525 - _ETHEREUMCLEARSIGNDEFINITIONREQUEST._serialized_end=2764 - _ETHEREUMCLEARSIGNDEFINITIONCHUNK._serialized_start=2766 - _ETHEREUMCLEARSIGNDEFINITIONCHUNK._serialized_end=2875 +DESCRIPTOR = _descriptor.FileDescriptor( + name='messages-ethereum.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n\x17messages-ethereum.proto\x1a\x0btypes.proto\"=\n\x12\x45thereumGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\"7\n\x0f\x45thereumAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\x0c\x12\x13\n\x0b\x61\x64\x64ress_str\x18\x02 \x01(\t\"\x95\x03\n\x0e\x45thereumSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x11\n\tgas_price\x18\x03 \x01(\x0c\x12\x11\n\tgas_limit\x18\x04 \x01(\x0c\x12\n\n\x02to\x18\x05 \x01(\x0c\x12\r\n\x05value\x18\x06 \x01(\x0c\x12\x1a\n\x12\x64\x61ta_initial_chunk\x18\x07 \x01(\x0c\x12\x13\n\x0b\x64\x61ta_length\x18\x08 \x01(\r\x12\x14\n\x0cto_address_n\x18\t \x03(\r\x12(\n\x0c\x61\x64\x64ress_type\x18\n \x01(\x0e\x32\x12.OutputAddressType\x12\x10\n\x08\x63hain_id\x18\x0c \x01(\r\x12\x17\n\x0fmax_fee_per_gas\x18\r \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x0e \x01(\x0c\x12\x13\n\x0btoken_value\x18\x64 \x01(\x0c\x12\x10\n\x08token_to\x18\x65 \x01(\x0c\x12\x16\n\x0etoken_shortcut\x18\x66 \x01(\t\x12\x0f\n\x07tx_type\x18g \x01(\r\x12\x0c\n\x04type\x18h \x01(\rJ\x04\x08\x0b\x10\x0c\"\x8c\x01\n\x11\x45thereumTxRequest\x12\x13\n\x0b\x64\x61ta_length\x18\x01 \x01(\r\x12\x13\n\x0bsignature_v\x18\x02 \x01(\r\x12\x13\n\x0bsignature_r\x18\x03 \x01(\x0c\x12\x13\n\x0bsignature_s\x18\x04 \x01(\x0c\x12\x0c\n\x04hash\x18\x05 \x01(\x0c\x12\x15\n\rsignature_der\x18\x06 \x01(\x0c\"#\n\rEthereumTxAck\x12\x12\n\ndata_chunk\x18\x01 \x01(\x0c\"V\n\x12\x45thereumTxMetadata\x12\x16\n\x0esigned_payload\x18\x01 \x01(\x0c\x12\x18\n\x10metadata_version\x18\x02 \x01(\r\x12\x0e\n\x06key_id\x18\x03 \x01(\r\"F\n\x13\x45thereumMetadataAck\x12\x16\n\x0e\x63lassification\x18\x01 \x02(\r\x12\x17\n\x0f\x64isplay_summary\x18\x02 \x01(\t\"\x8c\x01\n\x13LoadClearsignSigner\x12\x0e\n\x06key_id\x18\x01 \x01(\r\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\x0c\n\x04icon\x18\x04 \x01(\x0c\x12\x12\n\nicon_width\x18\x05 \x01(\r\x12\x13\n\x0bicon_height\x18\x06 \x01(\r\x12\x0f\n\x07persist\x18\x07 \x01(\x08\"9\n\x13\x45thereumSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\"L\n\x15\x45thereumVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\">\n\x18\x45thereumMessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"_\n\x15\x45thereumSignTypedHash\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1d\n\x15\x64omain_separator_hash\x18\x02 \x02(\x0c\x12\x14\n\x0cmessage_hash\x18\x03 \x01(\x0c\"\x8b\x01\n\x1a\x45thereumTypedDataSignature\x12\x11\n\tsignature\x18\x01 \x02(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x02(\t\x12\x1d\n\x15\x64omain_separator_hash\x18\x03 \x01(\x0c\x12\x14\n\x0chas_msg_hash\x18\x04 \x02(\x08\x12\x14\n\x0cmessage_hash\x18\x05 \x01(\x0c\"\x85\x01\n\x16\x45thereum712TypesValues\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x13\n\x0b\x65ip712types\x18\x02 \x02(\t\x12\x17\n\x0f\x65ip712primetype\x18\x03 \x02(\t\x12\x12\n\neip712data\x18\x04 \x02(\t\x12\x16\n\x0e\x65ip712typevals\x18\x05 \x02(\r\"b\n\x15\x45thereumSignTypedData\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cprimary_type\x18\x02 \x02(\t\x12 \n\x12metamask_v4_compat\x18\x03 \x01(\x08:\x04true\".\n\x1e\x45thereumTypedDataStructRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\"\xbe\x03\n\x1a\x45thereumTypedDataStructAck\x12\x41\n\x07members\x18\x01 \x03(\x0b\x32\x30.EthereumTypedDataStructAck.EthereumStructMember\x1a\x61\n\x14\x45thereumStructMember\x12;\n\x04type\x18\x01 \x02(\x0b\x32-.EthereumTypedDataStructAck.EthereumFieldType\x12\x0c\n\x04name\x18\x02 \x02(\t\x1a\x8d\x01\n\x11\x45thereumFieldType\x12?\n\tdata_type\x18\x01 \x02(\x0e\x32,.EthereumTypedDataStructAck.EthereumDataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12\x14\n\x0c\x61rray_levels\x18\x04 \x03(\r\"j\n\x10\x45thereumDataType\x12\x08\n\x04UINT\x10\x01\x12\x07\n\x03INT\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06STRING\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x0b\n\x07\x41\x44\x44RESS\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"4\n\x1d\x45thereumTypedDataValueRequest\x12\x13\n\x0bmember_path\x18\x01 \x03(\r\"*\n\x19\x45thereumTypedDataValueAck\x12\r\n\x05value\x18\x01 \x02(\x0c\"h\n\x1b\x45thereumClearSignDefinition\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c\"^\n\x1e\x45thereumClearSignDefinitionAck\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x13\n\x0bnext_offset\x18\x02 \x02(\r\x12\x10\n\x08\x63omplete\x18\x03 \x02(\x08\"\xef\x01\n\"EthereumClearSignDefinitionRequest\x12.\n\x04kind\x18\x01 \x02(\x0e\x32 .EthereumClearSignDefinitionKind\x12\x10\n\x08\x63hain_id\x18\x02 \x02(\x04\x12\x18\n\x10\x63ontract_address\x18\x03 \x01(\x0c\x12\x1d\n\x15selector_or_type_hash\x18\x04 \x01(\x0c\x12\x15\n\rdefinition_id\x18\x05 \x01(\x0c\x12\x0e\n\x06offset\x18\x06 \x02(\r\x12\x0e\n\x06length\x18\x07 \x02(\r\x12\x17\n\x0frecursion_depth\x18\x08 \x01(\r\"m\n EthereumClearSignDefinitionChunk\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c*s\n\x1f\x45thereumClearSignDefinitionKind\x12\x14\n\x10\x45RC7730_CALLDATA\x10\x01\x12\x12\n\x0e\x45RC7730_EIP712\x10\x02\x12\x11\n\rERC7730_TOKEN\x10\x03\x12\x13\n\x0f\x45RC7730_NETWORK\x10\x04\x42\x34\n\x1a\x63om.keepkey.deviceprotocolB\x16KeepKeyMessageEthereum') + , + dependencies=[types__pb2.DESCRIPTOR,]) + +_ETHEREUMCLEARSIGNDEFINITIONKIND = _descriptor.EnumDescriptor( + name='EthereumClearSignDefinitionKind', + full_name='EthereumClearSignDefinitionKind', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ERC7730_CALLDATA', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERC7730_EIP712', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERC7730_TOKEN', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERC7730_NETWORK', index=3, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2877, + serialized_end=2992, +) +_sym_db.RegisterEnumDescriptor(_ETHEREUMCLEARSIGNDEFINITIONKIND) + +EthereumClearSignDefinitionKind = enum_type_wrapper.EnumTypeWrapper(_ETHEREUMCLEARSIGNDEFINITIONKIND) +ERC7730_CALLDATA = 1 +ERC7730_EIP712 = 2 +ERC7730_TOKEN = 3 +ERC7730_NETWORK = 4 + + +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE = _descriptor.EnumDescriptor( + name='EthereumDataType', + full_name='EthereumTypedDataStructAck.EthereumDataType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='UINT', index=0, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INT', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='BYTES', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='STRING', index=3, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='BOOL', index=4, number=5, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ADDRESS', index=5, number=6, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ARRAY', index=6, number=7, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='STRUCT', index=7, number=8, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2116, + serialized_end=2222, +) +_sym_db.RegisterEnumDescriptor(_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE) + + +_ETHEREUMGETADDRESS = _descriptor.Descriptor( + name='EthereumGetAddress', + full_name='EthereumGetAddress', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='EthereumGetAddress.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='show_display', full_name='EthereumGetAddress.show_display', index=1, + number=2, 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=40, + serialized_end=101, +) + + +_ETHEREUMADDRESS = _descriptor.Descriptor( + name='EthereumAddress', + full_name='EthereumAddress', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='EthereumAddress.address', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='address_str', full_name='EthereumAddress.address_str', index=1, + number=2, 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=103, + serialized_end=158, +) + + +_ETHEREUMSIGNTX = _descriptor.Descriptor( + name='EthereumSignTx', + full_name='EthereumSignTx', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='EthereumSignTx.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='nonce', full_name='EthereumSignTx.nonce', 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='gas_price', full_name='EthereumSignTx.gas_price', 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='gas_limit', full_name='EthereumSignTx.gas_limit', 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='to', full_name='EthereumSignTx.to', index=4, + number=5, 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='EthereumSignTx.value', index=5, + number=6, 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='data_initial_chunk', full_name='EthereumSignTx.data_initial_chunk', 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='data_length', full_name='EthereumSignTx.data_length', index=7, + number=8, 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='to_address_n', full_name='EthereumSignTx.to_address_n', index=8, + number=9, 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='address_type', full_name='EthereumSignTx.address_type', index=9, + number=10, type=14, cpp_type=8, 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='chain_id', full_name='EthereumSignTx.chain_id', index=10, + 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='max_fee_per_gas', full_name='EthereumSignTx.max_fee_per_gas', index=11, + 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='max_priority_fee_per_gas', full_name='EthereumSignTx.max_priority_fee_per_gas', index=12, + 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), + _descriptor.FieldDescriptor( + name='token_value', full_name='EthereumSignTx.token_value', index=13, + number=100, 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='token_to', full_name='EthereumSignTx.token_to', index=14, + number=101, 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='token_shortcut', full_name='EthereumSignTx.token_shortcut', index=15, + number=102, 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), + _descriptor.FieldDescriptor( + name='tx_type', full_name='EthereumSignTx.tx_type', index=16, + number=103, 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='type', full_name='EthereumSignTx.type', index=17, + number=104, 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=161, + serialized_end=566, +) + + +_ETHEREUMTXREQUEST = _descriptor.Descriptor( + name='EthereumTxRequest', + full_name='EthereumTxRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='data_length', full_name='EthereumTxRequest.data_length', 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='signature_v', full_name='EthereumTxRequest.signature_v', 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='signature_r', full_name='EthereumTxRequest.signature_r', 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='signature_s', full_name='EthereumTxRequest.signature_s', 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='hash', full_name='EthereumTxRequest.hash', index=4, + number=5, 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_der', full_name='EthereumTxRequest.signature_der', index=5, + number=6, 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=569, + serialized_end=709, +) + + +_ETHEREUMTXACK = _descriptor.Descriptor( + name='EthereumTxAck', + full_name='EthereumTxAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='data_chunk', full_name='EthereumTxAck.data_chunk', 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=711, + serialized_end=746, +) + + +_ETHEREUMTXMETADATA = _descriptor.Descriptor( + name='EthereumTxMetadata', + full_name='EthereumTxMetadata', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signed_payload', full_name='EthereumTxMetadata.signed_payload', 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='metadata_version', full_name='EthereumTxMetadata.metadata_version', 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='key_id', full_name='EthereumTxMetadata.key_id', index=2, + number=3, 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=748, + serialized_end=834, +) + + +_ETHEREUMMETADATAACK = _descriptor.Descriptor( + name='EthereumMetadataAck', + full_name='EthereumMetadataAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='classification', full_name='EthereumMetadataAck.classification', index=0, + number=1, type=13, cpp_type=3, label=2, + 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='display_summary', full_name='EthereumMetadataAck.display_summary', index=1, + number=2, 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=836, + serialized_end=906, +) + + +_LOADCLEARSIGNSIGNER = _descriptor.Descriptor( + name='LoadClearsignSigner', + full_name='LoadClearsignSigner', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key_id', full_name='LoadClearsignSigner.key_id', 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='pubkey', full_name='LoadClearsignSigner.pubkey', 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='alias', full_name='LoadClearsignSigner.alias', index=2, + number=3, 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), + _descriptor.FieldDescriptor( + name='icon', full_name='LoadClearsignSigner.icon', 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='icon_width', full_name='LoadClearsignSigner.icon_width', index=4, + number=5, 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='icon_height', full_name='LoadClearsignSigner.icon_height', index=5, + number=6, 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='persist', full_name='LoadClearsignSigner.persist', index=6, + number=7, 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=909, + serialized_end=1049, +) + + +_ETHEREUMSIGNMESSAGE = _descriptor.Descriptor( + name='EthereumSignMessage', + full_name='EthereumSignMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='EthereumSignMessage.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='message', full_name='EthereumSignMessage.message', index=1, + number=2, type=12, cpp_type=9, label=2, + 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=1051, + serialized_end=1108, +) + + +_ETHEREUMVERIFYMESSAGE = _descriptor.Descriptor( + name='EthereumVerifyMessage', + full_name='EthereumVerifyMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='EthereumVerifyMessage.address', 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='EthereumVerifyMessage.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), + _descriptor.FieldDescriptor( + name='message', full_name='EthereumVerifyMessage.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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1110, + serialized_end=1186, +) + + +_ETHEREUMMESSAGESIGNATURE = _descriptor.Descriptor( + name='EthereumMessageSignature', + full_name='EthereumMessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='EthereumMessageSignature.address', 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='EthereumMessageSignature.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=1188, + serialized_end=1250, +) + + +_ETHEREUMSIGNTYPEDHASH = _descriptor.Descriptor( + name='EthereumSignTypedHash', + full_name='EthereumSignTypedHash', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='EthereumSignTypedHash.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='domain_separator_hash', full_name='EthereumSignTypedHash.domain_separator_hash', index=1, + number=2, type=12, cpp_type=9, label=2, + 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='message_hash', full_name='EthereumSignTypedHash.message_hash', 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=1252, + serialized_end=1347, +) + + +_ETHEREUMTYPEDDATASIGNATURE = _descriptor.Descriptor( + name='EthereumTypedDataSignature', + full_name='EthereumTypedDataSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signature', full_name='EthereumTypedDataSignature.signature', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='address', full_name='EthereumTypedDataSignature.address', index=1, + number=2, type=9, cpp_type=9, label=2, + 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), + _descriptor.FieldDescriptor( + name='domain_separator_hash', full_name='EthereumTypedDataSignature.domain_separator_hash', 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='has_msg_hash', full_name='EthereumTypedDataSignature.has_msg_hash', index=3, + number=4, type=8, cpp_type=7, label=2, + 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='message_hash', full_name='EthereumTypedDataSignature.message_hash', index=4, + number=5, 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=1350, + serialized_end=1489, +) + + +_ETHEREUM712TYPESVALUES = _descriptor.Descriptor( + name='Ethereum712TypesValues', + full_name='Ethereum712TypesValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='Ethereum712TypesValues.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='eip712types', full_name='Ethereum712TypesValues.eip712types', index=1, + number=2, type=9, cpp_type=9, label=2, + 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), + _descriptor.FieldDescriptor( + name='eip712primetype', full_name='Ethereum712TypesValues.eip712primetype', index=2, + number=3, type=9, cpp_type=9, label=2, + 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), + _descriptor.FieldDescriptor( + name='eip712data', full_name='Ethereum712TypesValues.eip712data', index=3, + number=4, type=9, cpp_type=9, label=2, + 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), + _descriptor.FieldDescriptor( + name='eip712typevals', full_name='Ethereum712TypesValues.eip712typevals', index=4, + number=5, type=13, cpp_type=3, label=2, + 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=1492, + serialized_end=1625, +) + + +_ETHEREUMSIGNTYPEDDATA = _descriptor.Descriptor( + name='EthereumSignTypedData', + full_name='EthereumSignTypedData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='EthereumSignTypedData.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='primary_type', full_name='EthereumSignTypedData.primary_type', index=1, + number=2, type=9, cpp_type=9, label=2, + 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), + _descriptor.FieldDescriptor( + name='metamask_v4_compat', full_name='EthereumSignTypedData.metamask_v4_compat', index=2, + number=3, 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=1627, + serialized_end=1725, +) + + +_ETHEREUMTYPEDDATASTRUCTREQUEST = _descriptor.Descriptor( + name='EthereumTypedDataStructRequest', + full_name='EthereumTypedDataStructRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='EthereumTypedDataStructRequest.name', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=1727, + serialized_end=1773, +) + + +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER = _descriptor.Descriptor( + name='EthereumStructMember', + full_name='EthereumTypedDataStructAck.EthereumStructMember', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='EthereumTypedDataStructAck.EthereumStructMember.type', index=0, + number=1, type=11, cpp_type=10, label=2, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='name', full_name='EthereumTypedDataStructAck.EthereumStructMember.name', index=1, + number=2, type=9, cpp_type=9, label=2, + 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=1873, + serialized_end=1970, +) + +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE = _descriptor.Descriptor( + name='EthereumFieldType', + full_name='EthereumTypedDataStructAck.EthereumFieldType', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='data_type', full_name='EthereumTypedDataStructAck.EthereumFieldType.data_type', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='size', full_name='EthereumTypedDataStructAck.EthereumFieldType.size', 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='struct_name', full_name='EthereumTypedDataStructAck.EthereumFieldType.struct_name', index=2, + number=3, 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), + _descriptor.FieldDescriptor( + name='array_levels', full_name='EthereumTypedDataStructAck.EthereumFieldType.array_levels', index=3, + number=4, 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1973, + serialized_end=2114, +) + +_ETHEREUMTYPEDDATASTRUCTACK = _descriptor.Descriptor( + name='EthereumTypedDataStructAck', + full_name='EthereumTypedDataStructAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='members', full_name='EthereumTypedDataStructAck.members', index=0, + number=1, type=11, cpp_type=10, 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), + ], + extensions=[ + ], + nested_types=[_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER, _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE, ], + enum_types=[ + _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE, + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1776, + serialized_end=2222, +) + + +_ETHEREUMTYPEDDATAVALUEREQUEST = _descriptor.Descriptor( + name='EthereumTypedDataValueRequest', + full_name='EthereumTypedDataValueRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='member_path', full_name='EthereumTypedDataValueRequest.member_path', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2224, + serialized_end=2276, +) + + +_ETHEREUMTYPEDDATAVALUEACK = _descriptor.Descriptor( + name='EthereumTypedDataValueAck', + full_name='EthereumTypedDataValueAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='EthereumTypedDataValueAck.value', index=0, + number=1, type=12, cpp_type=9, label=2, + 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=2278, + serialized_end=2320, +) + + +_ETHEREUMCLEARSIGNDEFINITION = _descriptor.Descriptor( + name='EthereumClearSignDefinition', + full_name='EthereumClearSignDefinition', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='definition_id', full_name='EthereumClearSignDefinition.definition_id', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='offset', full_name='EthereumClearSignDefinition.offset', index=1, + number=2, type=13, cpp_type=3, label=2, + 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_length', full_name='EthereumClearSignDefinition.total_length', index=2, + number=3, type=13, cpp_type=3, label=2, + 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='data', full_name='EthereumClearSignDefinition.data', index=3, + number=4, type=12, cpp_type=9, label=2, + 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=2322, + serialized_end=2426, +) + + +_ETHEREUMCLEARSIGNDEFINITIONACK = _descriptor.Descriptor( + name='EthereumClearSignDefinitionAck', + full_name='EthereumClearSignDefinitionAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='definition_id', full_name='EthereumClearSignDefinitionAck.definition_id', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='next_offset', full_name='EthereumClearSignDefinitionAck.next_offset', index=1, + number=2, type=13, cpp_type=3, label=2, + 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='complete', full_name='EthereumClearSignDefinitionAck.complete', index=2, + number=3, type=8, cpp_type=7, label=2, + 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=2428, + serialized_end=2522, +) + + +_ETHEREUMCLEARSIGNDEFINITIONREQUEST = _descriptor.Descriptor( + name='EthereumClearSignDefinitionRequest', + full_name='EthereumClearSignDefinitionRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='kind', full_name='EthereumClearSignDefinitionRequest.kind', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='chain_id', full_name='EthereumClearSignDefinitionRequest.chain_id', index=1, + number=2, type=4, cpp_type=4, label=2, + 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='contract_address', full_name='EthereumClearSignDefinitionRequest.contract_address', 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='selector_or_type_hash', full_name='EthereumClearSignDefinitionRequest.selector_or_type_hash', 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='definition_id', full_name='EthereumClearSignDefinitionRequest.definition_id', index=4, + number=5, 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='offset', full_name='EthereumClearSignDefinitionRequest.offset', index=5, + number=6, type=13, cpp_type=3, label=2, + 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='length', full_name='EthereumClearSignDefinitionRequest.length', index=6, + number=7, type=13, cpp_type=3, label=2, + 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='recursion_depth', full_name='EthereumClearSignDefinitionRequest.recursion_depth', index=7, + number=8, 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=2525, + serialized_end=2764, +) + + +_ETHEREUMCLEARSIGNDEFINITIONCHUNK = _descriptor.Descriptor( + name='EthereumClearSignDefinitionChunk', + full_name='EthereumClearSignDefinitionChunk', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='definition_id', full_name='EthereumClearSignDefinitionChunk.definition_id', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='offset', full_name='EthereumClearSignDefinitionChunk.offset', index=1, + number=2, type=13, cpp_type=3, label=2, + 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_length', full_name='EthereumClearSignDefinitionChunk.total_length', index=2, + number=3, type=13, cpp_type=3, label=2, + 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='data', full_name='EthereumClearSignDefinitionChunk.data', index=3, + number=4, type=12, cpp_type=9, label=2, + 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=2766, + serialized_end=2875, +) + +_ETHEREUMSIGNTX.fields_by_name['address_type'].enum_type = types__pb2._OUTPUTADDRESSTYPE +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER.fields_by_name['type'].message_type = _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER.containing_type = _ETHEREUMTYPEDDATASTRUCTACK +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE.fields_by_name['data_type'].enum_type = _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE.containing_type = _ETHEREUMTYPEDDATASTRUCTACK +_ETHEREUMTYPEDDATASTRUCTACK.fields_by_name['members'].message_type = _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER +_ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMDATATYPE.containing_type = _ETHEREUMTYPEDDATASTRUCTACK +_ETHEREUMCLEARSIGNDEFINITIONREQUEST.fields_by_name['kind'].enum_type = _ETHEREUMCLEARSIGNDEFINITIONKIND +DESCRIPTOR.message_types_by_name['EthereumGetAddress'] = _ETHEREUMGETADDRESS +DESCRIPTOR.message_types_by_name['EthereumAddress'] = _ETHEREUMADDRESS +DESCRIPTOR.message_types_by_name['EthereumSignTx'] = _ETHEREUMSIGNTX +DESCRIPTOR.message_types_by_name['EthereumTxRequest'] = _ETHEREUMTXREQUEST +DESCRIPTOR.message_types_by_name['EthereumTxAck'] = _ETHEREUMTXACK +DESCRIPTOR.message_types_by_name['EthereumTxMetadata'] = _ETHEREUMTXMETADATA +DESCRIPTOR.message_types_by_name['EthereumMetadataAck'] = _ETHEREUMMETADATAACK +DESCRIPTOR.message_types_by_name['LoadClearsignSigner'] = _LOADCLEARSIGNSIGNER +DESCRIPTOR.message_types_by_name['EthereumSignMessage'] = _ETHEREUMSIGNMESSAGE +DESCRIPTOR.message_types_by_name['EthereumVerifyMessage'] = _ETHEREUMVERIFYMESSAGE +DESCRIPTOR.message_types_by_name['EthereumMessageSignature'] = _ETHEREUMMESSAGESIGNATURE +DESCRIPTOR.message_types_by_name['EthereumSignTypedHash'] = _ETHEREUMSIGNTYPEDHASH +DESCRIPTOR.message_types_by_name['EthereumTypedDataSignature'] = _ETHEREUMTYPEDDATASIGNATURE +DESCRIPTOR.message_types_by_name['Ethereum712TypesValues'] = _ETHEREUM712TYPESVALUES +DESCRIPTOR.message_types_by_name['EthereumSignTypedData'] = _ETHEREUMSIGNTYPEDDATA +DESCRIPTOR.message_types_by_name['EthereumTypedDataStructRequest'] = _ETHEREUMTYPEDDATASTRUCTREQUEST +DESCRIPTOR.message_types_by_name['EthereumTypedDataStructAck'] = _ETHEREUMTYPEDDATASTRUCTACK +DESCRIPTOR.message_types_by_name['EthereumTypedDataValueRequest'] = _ETHEREUMTYPEDDATAVALUEREQUEST +DESCRIPTOR.message_types_by_name['EthereumTypedDataValueAck'] = _ETHEREUMTYPEDDATAVALUEACK +DESCRIPTOR.message_types_by_name['EthereumClearSignDefinition'] = _ETHEREUMCLEARSIGNDEFINITION +DESCRIPTOR.message_types_by_name['EthereumClearSignDefinitionAck'] = _ETHEREUMCLEARSIGNDEFINITIONACK +DESCRIPTOR.message_types_by_name['EthereumClearSignDefinitionRequest'] = _ETHEREUMCLEARSIGNDEFINITIONREQUEST +DESCRIPTOR.message_types_by_name['EthereumClearSignDefinitionChunk'] = _ETHEREUMCLEARSIGNDEFINITIONCHUNK +DESCRIPTOR.enum_types_by_name['EthereumClearSignDefinitionKind'] = _ETHEREUMCLEARSIGNDEFINITIONKIND +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +EthereumGetAddress = _reflection.GeneratedProtocolMessageType('EthereumGetAddress', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMGETADDRESS, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumGetAddress) + )) +_sym_db.RegisterMessage(EthereumGetAddress) + +EthereumAddress = _reflection.GeneratedProtocolMessageType('EthereumAddress', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMADDRESS, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumAddress) + )) +_sym_db.RegisterMessage(EthereumAddress) + +EthereumSignTx = _reflection.GeneratedProtocolMessageType('EthereumSignTx', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMSIGNTX, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumSignTx) + )) +_sym_db.RegisterMessage(EthereumSignTx) + +EthereumTxRequest = _reflection.GeneratedProtocolMessageType('EthereumTxRequest', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTXREQUEST, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTxRequest) + )) +_sym_db.RegisterMessage(EthereumTxRequest) + +EthereumTxAck = _reflection.GeneratedProtocolMessageType('EthereumTxAck', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTXACK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTxAck) + )) +_sym_db.RegisterMessage(EthereumTxAck) + +EthereumTxMetadata = _reflection.GeneratedProtocolMessageType('EthereumTxMetadata', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTXMETADATA, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTxMetadata) + )) +_sym_db.RegisterMessage(EthereumTxMetadata) + +EthereumMetadataAck = _reflection.GeneratedProtocolMessageType('EthereumMetadataAck', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMMETADATAACK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumMetadataAck) + )) +_sym_db.RegisterMessage(EthereumMetadataAck) + +LoadClearsignSigner = _reflection.GeneratedProtocolMessageType('LoadClearsignSigner', (_message.Message,), dict( + DESCRIPTOR = _LOADCLEARSIGNSIGNER, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:LoadClearsignSigner) + )) +_sym_db.RegisterMessage(LoadClearsignSigner) + +EthereumSignMessage = _reflection.GeneratedProtocolMessageType('EthereumSignMessage', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMSIGNMESSAGE, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumSignMessage) + )) +_sym_db.RegisterMessage(EthereumSignMessage) + +EthereumVerifyMessage = _reflection.GeneratedProtocolMessageType('EthereumVerifyMessage', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMVERIFYMESSAGE, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumVerifyMessage) + )) +_sym_db.RegisterMessage(EthereumVerifyMessage) + +EthereumMessageSignature = _reflection.GeneratedProtocolMessageType('EthereumMessageSignature', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMMESSAGESIGNATURE, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumMessageSignature) + )) +_sym_db.RegisterMessage(EthereumMessageSignature) + +EthereumSignTypedHash = _reflection.GeneratedProtocolMessageType('EthereumSignTypedHash', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMSIGNTYPEDHASH, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumSignTypedHash) + )) +_sym_db.RegisterMessage(EthereumSignTypedHash) + +EthereumTypedDataSignature = _reflection.GeneratedProtocolMessageType('EthereumTypedDataSignature', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATASIGNATURE, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataSignature) + )) +_sym_db.RegisterMessage(EthereumTypedDataSignature) + +Ethereum712TypesValues = _reflection.GeneratedProtocolMessageType('Ethereum712TypesValues', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUM712TYPESVALUES, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:Ethereum712TypesValues) + )) +_sym_db.RegisterMessage(Ethereum712TypesValues) + +EthereumSignTypedData = _reflection.GeneratedProtocolMessageType('EthereumSignTypedData', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMSIGNTYPEDDATA, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumSignTypedData) + )) +_sym_db.RegisterMessage(EthereumSignTypedData) + +EthereumTypedDataStructRequest = _reflection.GeneratedProtocolMessageType('EthereumTypedDataStructRequest', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATASTRUCTREQUEST, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataStructRequest) + )) +_sym_db.RegisterMessage(EthereumTypedDataStructRequest) + +EthereumTypedDataStructAck = _reflection.GeneratedProtocolMessageType('EthereumTypedDataStructAck', (_message.Message,), dict( + + EthereumStructMember = _reflection.GeneratedProtocolMessageType('EthereumStructMember', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMSTRUCTMEMBER, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataStructAck.EthereumStructMember) + )) + , + + EthereumFieldType = _reflection.GeneratedProtocolMessageType('EthereumFieldType', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATASTRUCTACK_ETHEREUMFIELDTYPE, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataStructAck.EthereumFieldType) + )) + , + DESCRIPTOR = _ETHEREUMTYPEDDATASTRUCTACK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataStructAck) + )) +_sym_db.RegisterMessage(EthereumTypedDataStructAck) +_sym_db.RegisterMessage(EthereumTypedDataStructAck.EthereumStructMember) +_sym_db.RegisterMessage(EthereumTypedDataStructAck.EthereumFieldType) + +EthereumTypedDataValueRequest = _reflection.GeneratedProtocolMessageType('EthereumTypedDataValueRequest', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATAVALUEREQUEST, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataValueRequest) + )) +_sym_db.RegisterMessage(EthereumTypedDataValueRequest) + +EthereumTypedDataValueAck = _reflection.GeneratedProtocolMessageType('EthereumTypedDataValueAck', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMTYPEDDATAVALUEACK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumTypedDataValueAck) + )) +_sym_db.RegisterMessage(EthereumTypedDataValueAck) + +EthereumClearSignDefinition = _reflection.GeneratedProtocolMessageType('EthereumClearSignDefinition', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMCLEARSIGNDEFINITION, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumClearSignDefinition) + )) +_sym_db.RegisterMessage(EthereumClearSignDefinition) + +EthereumClearSignDefinitionAck = _reflection.GeneratedProtocolMessageType('EthereumClearSignDefinitionAck', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMCLEARSIGNDEFINITIONACK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumClearSignDefinitionAck) + )) +_sym_db.RegisterMessage(EthereumClearSignDefinitionAck) + +EthereumClearSignDefinitionRequest = _reflection.GeneratedProtocolMessageType('EthereumClearSignDefinitionRequest', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMCLEARSIGNDEFINITIONREQUEST, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumClearSignDefinitionRequest) + )) +_sym_db.RegisterMessage(EthereumClearSignDefinitionRequest) + +EthereumClearSignDefinitionChunk = _reflection.GeneratedProtocolMessageType('EthereumClearSignDefinitionChunk', (_message.Message,), dict( + DESCRIPTOR = _ETHEREUMCLEARSIGNDEFINITIONCHUNK, + __module__ = 'messages_ethereum_pb2' + # @@protoc_insertion_point(class_scope:EthereumClearSignDefinitionChunk) + )) +_sym_db.RegisterMessage(EthereumClearSignDefinitionChunk) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\026KeepKeyMessageEthereum')) # @@protoc_insertion_point(module_scope) diff --git a/keepkeylib/messages_pb2.py b/keepkeylib/messages_pb2.py index ab16288a..e3b086a7 100644 --- a/keepkeylib/messages_pb2.py +++ b/keepkeylib/messages_pb2.py @@ -1,11 +1,14 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: messages.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool +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() @@ -14,602 +17,5253 @@ from . import types_pb2 as types__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xe1\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\x12\x18\n\x10supports_taproot\x18\x1b \x01(\x08\x12\x1b\n\x13supports_dice_modes\x18\x1c \x01(\x08\"*\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\"\x8a\x02\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\x12\x14\n\x0c\x64ice_entropy\x18\n \x01(\x08\x12\x11\n\tdice_only\x18\x0b \x01(\x08\"\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\"5\n\x10GetBip85Mnemonic\x12\x12\n\nword_count\x18\x01 \x02(\r\x12\r\n\x05index\x18\x02 \x02(\r\"!\n\rBip85Mnemonic\x12\x10\n\x08mnemonic\x18\x01 \x02(\t\"\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\"2\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\x12\r\n\x05input\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\xec\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\x12\x13\n\x0b\x64ice_digest\x18\x0f \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\"\x1f\n\x1d\x43learsignAttestorGetPublicKey\"0\n\x1a\x43learsignAttestorPublicKey\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"(\n\x15\x43learsignAttestorSign\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\"C\n\x1a\x43learsignAttestorSignature\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x12\n\npublic_key\x18\x02 \x01(\x0c*\xc3\x46\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\x1eMessageType_EthereumTxMetadata\x10s\x1a\x04\x90\xb5\x18\x01\x12)\n\x1fMessageType_EthereumMetadataAck\x10t\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_LoadClearsignSigner\x10u\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTypedData\x10\xa8\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumTypedDataStructRequest\x10\xa9\r\x1a\x04\x98\xb5\x18\x01\x12\x31\n&MessageType_EthereumTypedDataStructAck\x10\xaa\r\x1a\x04\x90\xb5\x18\x01\x12\x34\n)MessageType_EthereumTypedDataValueRequest\x10\xab\r\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_EthereumTypedDataValueAck\x10\xac\r\x1a\x04\x90\xb5\x18\x01\x12\x32\n\'MessageType_EthereumClearSignDefinition\x10\xad\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumClearSignDefinitionAck\x10\xae\r\x1a\x04\x98\xb5\x18\x01\x12\x39\n.MessageType_EthereumClearSignDefinitionRequest\x10\xaf\r\x1a\x04\x98\xb5\x18\x01\x12\x37\n,MessageType_EthereumClearSignDefinitionChunk\x10\xb0\r\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_GetBip85Mnemonic\x10x\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_Bip85Mnemonic\x10y\x1a\x04\x98\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\x30\n%MessageType_SolanaSignOffchainMessage\x10\xf4\x05\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_SolanaOffchainMessageSignature\x10\xf5\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\x12,\n!MessageType_ZcashTransparentInput\x10\x9a\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentSigned\x10\x9b\n\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_ZcashDisplayAddress\x10\x9c\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_ZcashAddress\x10\x9d\n\x1a\x04\x98\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentOutput\x10\x9e\n\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ZcashTransparentAck\x10\x9f\n\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TronGetAddress\x10\xf8\n\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TronAddress\x10\xf9\n\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_TronSignTx\x10\xfa\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_TronSignedTx\x10\xfb\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_TronSignMessage\x10\xfc\n\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TronMessageSignature\x10\xfd\n\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_TronVerifyMessage\x10\xfe\n\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TronSignTypedHash\x10\xff\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_TronTypedDataSignature\x10\x80\x0b\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_TonGetAddress\x10\xdc\x0b\x1a\x04\x90\xb5\x18\x01\x12!\n\x16MessageType_TonAddress\x10\xdd\x0b\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_TonSignTx\x10\xde\x0b\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TonSignedTx\x10\xdf\x0b\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TonSignMessage\x10\xe0\x0b\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_TonMessageSignature\x10\xe1\x0b\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_HiveGetPublicKey\x10\xc0\x0c\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_HivePublicKey\x10\xc1\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_HiveSignTx\x10\xc2\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_HiveSignedTx\x10\xc3\x0c\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_HiveGetPublicKeys\x10\xc4\x0c\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_HivePublicKeys\x10\xc5\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountCreate\x10\xc6\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountCreate\x10\xc7\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountUpdate\x10\xc8\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountUpdate\x10\xc9\x0c\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NearGetAddress\x10\xca\x0c\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NearAddress\x10\xcb\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NearSignTx\x10\xcc\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NearSignedTx\x10\xcd\x0c\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_HiveSignMessage\x10\xce\x0c\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_HiveSignedMessage\x10\xcf\x0c\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_HiveSignOperations\x10\xd0\x0c\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_HiveSignedOperations\x10\xd1\x0c\x1a\x04\x98\xb5\x18\x01\x12\x34\n)MessageType_ClearsignAttestorGetPublicKey\x10\xa4\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorPublicKey\x10\xa5\r\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ClearsignAttestorSign\x10\xa6\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorSignature\x10\xa7\r\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'messages_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\032com.keepkey.deviceprotocolB\016KeepKeyMessage' - _MESSAGETYPE.values_by_name["MessageType_Initialize"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Initialize"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Ping"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Ping"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Success"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Success"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Failure"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Failure"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ChangePin"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ChangePin"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_WipeDevice"]._options = None - _MESSAGETYPE.values_by_name["MessageType_WipeDevice"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_FirmwareErase"]._options = None - _MESSAGETYPE.values_by_name["MessageType_FirmwareErase"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_FirmwareUpload"]._options = None - _MESSAGETYPE.values_by_name["MessageType_FirmwareUpload"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetEntropy"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetEntropy"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Entropy"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Entropy"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetPublicKey"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_PublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_PublicKey"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_LoadDevice"]._options = None - _MESSAGETYPE.values_by_name["MessageType_LoadDevice"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ResetDevice"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ResetDevice"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Features"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Features"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_PinMatrixRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_PinMatrixRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_PinMatrixAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_PinMatrixAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Cancel"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Cancel"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TxRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TxRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TxAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TxAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CipherKeyValue"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CipherKeyValue"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ClearSession"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ClearSession"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ApplySettings"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ApplySettings"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ButtonRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ButtonRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ButtonAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ButtonAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Address"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Address"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EntropyRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EntropyRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EntropyAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EntropyAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_VerifyMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_VerifyMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_PassphraseRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_PassphraseRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_PassphraseAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_PassphraseAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RecoveryDevice"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RecoveryDevice"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_WordRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_WordRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_WordAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_WordAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CipheredKeyValue"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CipheredKeyValue"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EncryptMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EncryptMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EncryptedMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EncryptedMessage"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DecryptMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DecryptMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DecryptedMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DecryptedMessage"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SignIdentity"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SignIdentity"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SignedIdentity"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SignedIdentity"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetFeatures"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetFeatures"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTxRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTxRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTxAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTxAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CharacterRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CharacterRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CharacterAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CharacterAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RawTxAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RawTxAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ApplyPolicies"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ApplyPolicies"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_FlashHash"]._options = None - _MESSAGETYPE.values_by_name["MessageType_FlashHash"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_FlashWrite"]._options = None - _MESSAGETYPE.values_by_name["MessageType_FlashWrite"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_FlashHashResponse"]._options = None - _MESSAGETYPE.values_by_name["MessageType_FlashHashResponse"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDump"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDump"]._serialized_options = b'\240\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDumpResponse"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDumpResponse"]._serialized_options = b'\250\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SoftReset"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SoftReset"]._serialized_options = b'\240\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkDecision"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkDecision"]._serialized_options = b'\240\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkGetState"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkGetState"]._serialized_options = b'\240\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkState"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkState"]._serialized_options = b'\250\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkStop"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkStop"]._serialized_options = b'\240\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkLog"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkLog"]._serialized_options = b'\250\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFillConfig"]._options = None - _MESSAGETYPE.values_by_name["MessageType_DebugLinkFillConfig"]._serialized_options = b'\250\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetCoinTable"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetCoinTable"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CoinTable"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CoinTable"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumSignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumSignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumVerifyMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumVerifyMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumMessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumMessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ChangeWipeCode"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ChangeWipeCode"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedHash"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedHash"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Ethereum712TypesValues"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Ethereum712TypesValues"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTxMetadata"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTxMetadata"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumMetadataAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumMetadataAck"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_LoadClearsignSigner"]._options = None - _MESSAGETYPE.values_by_name["MessageType_LoadClearsignSigner"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedData"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedData"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinition"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinition"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionAck"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionChunk"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionChunk"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_GetBip85Mnemonic"]._options = None - _MESSAGETYPE.values_by_name["MessageType_GetBip85Mnemonic"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_Bip85Mnemonic"]._options = None - _MESSAGETYPE.values_by_name["MessageType_Bip85Mnemonic"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RippleGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RippleGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RippleAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RippleAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RippleSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RippleSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_RippleSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_RippleSignedTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainMsgRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainMsgRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainMsgAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainMsgAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ThorchainSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ThorchainSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosGetPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosGetPublicKey"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosPublicKey"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosTxActionRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosTxActionRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosTxActionAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosTxActionAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_EosSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_EosSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NanoGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NanoGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NanoAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NanoAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NanoSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NanoSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NanoSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NanoSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaSignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaSignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaMessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaSignOffchainMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaSignOffchainMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceGetPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceGetPublicKey"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinancePublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinancePublicKey"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceTxRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceTxRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceTransferMsg"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceTransferMsg"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceOrderMsg"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceOrderMsg"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceCancelMsg"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceCancelMsg"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_BinanceSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_BinanceSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgDelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgDelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgUndelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgUndelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRedelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRedelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRewards"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgRewards"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgIBCTransfer"]._options = None - _MESSAGETYPE.values_by_name["MessageType_CosmosMsgIBCTransfer"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgSend"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgSend"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgDelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgDelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgUndelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgUndelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRedelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRedelegate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRewards"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgRewards"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgIBCTransfer"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TendermintMsgIBCTransfer"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSend"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSend"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgDelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgDelegate"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgUndelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgUndelegate"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRedelegate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRedelegate"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRewards"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRewards"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPAdd"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPAdd"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPRemove"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPRemove"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPStake"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPStake"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPUnstake"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPUnstake"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgIBCTransfer"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgIBCTransfer"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSwap"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSwap"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_OsmosisSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_OsmosisSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainMsgRequest"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainMsgRequest"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainMsgAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainMsgAck"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_MayachainSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_MayachainSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashSignPCZT"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashSignPCZT"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashPCZTAction"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashPCZTAction"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashPCZTActionAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashPCZTActionAck"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashSignedPCZT"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashSignedPCZT"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashGetOrchardFVK"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashGetOrchardFVK"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashOrchardFVK"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashOrchardFVK"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentInput"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentInput"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentSigned"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentSigned"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashDisplayAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashDisplayAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentOutput"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentOutput"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentAck"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ZcashTransparentAck"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronSignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronSignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonSignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonSignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKey"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HivePublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HivePublicKey"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKeys"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKeys"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HivePublicKeys"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HivePublicKeys"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignAccountCreate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignAccountCreate"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountCreate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountCreate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignAccountUpdate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignAccountUpdate"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountUpdate"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountUpdate"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NearGetAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NearGetAddress"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NearAddress"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NearAddress"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NearSignTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NearSignTx"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_NearSignedTx"]._options = None - _MESSAGETYPE.values_by_name["MessageType_NearSignedTx"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignMessage"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignedMessage"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignedMessage"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignOperations"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignOperations"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_HiveSignedOperations"]._options = None - _MESSAGETYPE.values_by_name["MessageType_HiveSignedOperations"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorGetPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorGetPublicKey"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorPublicKey"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorPublicKey"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSign"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSign"]._serialized_options = b'\220\265\030\001' - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSignature"]._options = None - _MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSignature"]._serialized_options = b'\230\265\030\001' - _MESSAGETYPE._serialized_start=5517 - _MESSAGETYPE._serialized_end=14544 - _INITIALIZE._serialized_start=31 - _INITIALIZE._serialized_end=43 - _GETFEATURES._serialized_start=45 - _GETFEATURES._serialized_end=58 - _FEATURES._serialized_start=61 - _FEATURES._serialized_end=670 - _GETCOINTABLE._serialized_start=672 - _GETCOINTABLE._serialized_end=714 - _COINTABLE._serialized_start=716 - _COINTABLE._serialized_end=792 - _CLEARSESSION._serialized_start=794 - _CLEARSESSION._serialized_end=808 - _APPLYSETTINGS._serialized_start=810 - _APPLYSETTINGS._serialized_end=931 - _CHANGEPIN._serialized_start=933 - _CHANGEPIN._serialized_end=960 - _PING._serialized_start=963 - _PING._serialized_end=1098 - _SUCCESS._serialized_start=1100 - _SUCCESS._serialized_end=1126 - _FAILURE._serialized_start=1128 - _FAILURE._serialized_end=1182 - _BUTTONREQUEST._serialized_start=1184 - _BUTTONREQUEST._serialized_end=1247 - _BUTTONACK._serialized_start=1249 - _BUTTONACK._serialized_end=1260 - _PINMATRIXREQUEST._serialized_start=1262 - _PINMATRIXREQUEST._serialized_end=1317 - _PINMATRIXACK._serialized_start=1319 - _PINMATRIXACK._serialized_end=1346 - _CANCEL._serialized_start=1348 - _CANCEL._serialized_end=1356 - _PASSPHRASEREQUEST._serialized_start=1358 - _PASSPHRASEREQUEST._serialized_end=1377 - _PASSPHRASEACK._serialized_start=1379 - _PASSPHRASEACK._serialized_end=1414 - _GETENTROPY._serialized_start=1416 - _GETENTROPY._serialized_end=1442 - _ENTROPY._serialized_start=1444 - _ENTROPY._serialized_end=1470 - _GETPUBLICKEY._serialized_start=1473 - _GETPUBLICKEY._serialized_end=1635 - _PUBLICKEY._serialized_start=1637 - _PUBLICKEY._serialized_end=1689 - _GETADDRESS._serialized_start=1692 - _GETADDRESS._serialized_end=1871 - _ADDRESS._serialized_start=1873 - _ADDRESS._serialized_end=1899 - _WIPEDEVICE._serialized_start=1901 - _WIPEDEVICE._serialized_end=1913 - _LOADDEVICE._serialized_start=1916 - _LOADDEVICE._serialized_end=2103 - _RESETDEVICE._serialized_start=2106 - _RESETDEVICE._serialized_end=2372 - _ENTROPYREQUEST._serialized_start=2374 - _ENTROPYREQUEST._serialized_end=2390 - _ENTROPYACK._serialized_start=2392 - _ENTROPYACK._serialized_end=2421 - _RECOVERYDEVICE._serialized_start=2424 - _RECOVERYDEVICE._serialized_end=2679 - _WORDREQUEST._serialized_start=2681 - _WORDREQUEST._serialized_end=2694 - _WORDACK._serialized_start=2696 - _WORDACK._serialized_end=2719 - _CHARACTERREQUEST._serialized_start=2721 - _CHARACTERREQUEST._serialized_end=2780 - _CHARACTERACK._serialized_start=2782 - _CHARACTERACK._serialized_end=2845 - _SIGNMESSAGE._serialized_start=2848 - _SIGNMESSAGE._serialized_end=2978 - _VERIFYMESSAGE._serialized_start=2980 - _VERIFYMESSAGE._serialized_end=3076 - _MESSAGESIGNATURE._serialized_start=3078 - _MESSAGESIGNATURE._serialized_end=3132 - _ENCRYPTMESSAGE._serialized_start=3134 - _ENCRYPTMESSAGE._serialized_end=3252 - _ENCRYPTEDMESSAGE._serialized_start=3254 - _ENCRYPTEDMESSAGE._serialized_end=3318 - _DECRYPTMESSAGE._serialized_start=3320 - _DECRYPTMESSAGE._serialized_end=3401 - _DECRYPTEDMESSAGE._serialized_start=3403 - _DECRYPTEDMESSAGE._serialized_end=3455 - _CIPHERKEYVALUE._serialized_start=3458 - _CIPHERKEYVALUE._serialized_end=3598 - _CIPHEREDKEYVALUE._serialized_start=3600 - _CIPHEREDKEYVALUE._serialized_end=3633 - _GETBIP85MNEMONIC._serialized_start=3635 - _GETBIP85MNEMONIC._serialized_end=3688 - _BIP85MNEMONIC._serialized_start=3690 - _BIP85MNEMONIC._serialized_end=3723 - _SIGNTX._serialized_start=3726 - _SIGNTX._serialized_end=3932 - _TXREQUEST._serialized_start=3935 - _TXREQUEST._serialized_end=4068 - _TXACK._serialized_start=4070 - _TXACK._serialized_end=4107 - _RAWTXACK._serialized_start=4109 - _RAWTXACK._serialized_end=4152 - _SIGNIDENTITY._serialized_start=4154 - _SIGNIDENTITY._serialized_end=4279 - _SIGNEDIDENTITY._serialized_start=4281 - _SIGNEDIDENTITY._serialized_end=4353 - _APPLYPOLICIES._serialized_start=4355 - _APPLYPOLICIES._serialized_end=4399 - _FLASHHASH._serialized_start=4401 - _FLASHHASH._serialized_end=4464 - _FLASHWRITE._serialized_start=4466 - _FLASHWRITE._serialized_end=4524 - _FLASHHASHRESPONSE._serialized_start=4526 - _FLASHHASHRESPONSE._serialized_end=4559 - _DEBUGLINKFLASHDUMP._serialized_start=4561 - _DEBUGLINKFLASHDUMP._serialized_end=4614 - _DEBUGLINKFLASHDUMPRESPONSE._serialized_start=4616 - _DEBUGLINKFLASHDUMPRESPONSE._serialized_end=4658 - _SOFTRESET._serialized_start=4660 - _SOFTRESET._serialized_end=4671 - _FIRMWAREERASE._serialized_start=4673 - _FIRMWAREERASE._serialized_end=4688 - _FIRMWAREUPLOAD._serialized_start=4690 - _FIRMWAREUPLOAD._serialized_end=4745 - _DEBUGLINKDECISION._serialized_start=4747 - _DEBUGLINKDECISION._serialized_end=4797 - _DEBUGLINKGETSTATE._serialized_start=4799 - _DEBUGLINKGETSTATE._serialized_end=4818 - _DEBUGLINKSTATE._serialized_start=4821 - _DEBUGLINKSTATE._serialized_end=5185 - _DEBUGLINKSTOP._serialized_start=5187 - _DEBUGLINKSTOP._serialized_end=5202 - _DEBUGLINKLOG._serialized_start=5204 - _DEBUGLINKLOG._serialized_end=5263 - _DEBUGLINKFILLCONFIG._serialized_start=5265 - _DEBUGLINKFILLCONFIG._serialized_end=5286 - _CHANGEWIPECODE._serialized_start=5288 - _CHANGEWIPECODE._serialized_end=5320 - _CLEARSIGNATTESTORGETPUBLICKEY._serialized_start=5322 - _CLEARSIGNATTESTORGETPUBLICKEY._serialized_end=5353 - _CLEARSIGNATTESTORPUBLICKEY._serialized_start=5355 - _CLEARSIGNATTESTORPUBLICKEY._serialized_end=5403 - _CLEARSIGNATTESTORSIGN._serialized_start=5405 - _CLEARSIGNATTESTORSIGN._serialized_end=5445 - _CLEARSIGNATTESTORSIGNATURE._serialized_start=5447 - _CLEARSIGNATTESTORSIGNATURE._serialized_end=5514 +DESCRIPTOR = _descriptor.FileDescriptor( + name='messages.proto', + package='', + syntax='proto2', + serialized_pb=_b('\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xe1\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\x12\x18\n\x10supports_taproot\x18\x1b \x01(\x08\x12\x1b\n\x13supports_dice_modes\x18\x1c \x01(\x08\"*\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\"\x8a\x02\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\x12\x14\n\x0c\x64ice_entropy\x18\n \x01(\x08\x12\x11\n\tdice_only\x18\x0b \x01(\x08\"\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\"5\n\x10GetBip85Mnemonic\x12\x12\n\nword_count\x18\x01 \x02(\r\x12\r\n\x05index\x18\x02 \x02(\r\"!\n\rBip85Mnemonic\x12\x10\n\x08mnemonic\x18\x01 \x02(\t\"\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\"2\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\x12\r\n\x05input\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\xec\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\x12\x13\n\x0b\x64ice_digest\x18\x0f \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\"\x1f\n\x1d\x43learsignAttestorGetPublicKey\"0\n\x1a\x43learsignAttestorPublicKey\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"(\n\x15\x43learsignAttestorSign\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\"C\n\x1a\x43learsignAttestorSignature\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x12\n\npublic_key\x18\x02 \x01(\x0c*\xc3\x46\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\x1eMessageType_EthereumTxMetadata\x10s\x1a\x04\x90\xb5\x18\x01\x12)\n\x1fMessageType_EthereumMetadataAck\x10t\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_LoadClearsignSigner\x10u\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTypedData\x10\xa8\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumTypedDataStructRequest\x10\xa9\r\x1a\x04\x98\xb5\x18\x01\x12\x31\n&MessageType_EthereumTypedDataStructAck\x10\xaa\r\x1a\x04\x90\xb5\x18\x01\x12\x34\n)MessageType_EthereumTypedDataValueRequest\x10\xab\r\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_EthereumTypedDataValueAck\x10\xac\r\x1a\x04\x90\xb5\x18\x01\x12\x32\n\'MessageType_EthereumClearSignDefinition\x10\xad\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumClearSignDefinitionAck\x10\xae\r\x1a\x04\x98\xb5\x18\x01\x12\x39\n.MessageType_EthereumClearSignDefinitionRequest\x10\xaf\r\x1a\x04\x98\xb5\x18\x01\x12\x37\n,MessageType_EthereumClearSignDefinitionChunk\x10\xb0\r\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_GetBip85Mnemonic\x10x\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_Bip85Mnemonic\x10y\x1a\x04\x98\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\x30\n%MessageType_SolanaSignOffchainMessage\x10\xf4\x05\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_SolanaOffchainMessageSignature\x10\xf5\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\x12,\n!MessageType_ZcashTransparentInput\x10\x9a\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentSigned\x10\x9b\n\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_ZcashDisplayAddress\x10\x9c\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_ZcashAddress\x10\x9d\n\x1a\x04\x98\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentOutput\x10\x9e\n\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ZcashTransparentAck\x10\x9f\n\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TronGetAddress\x10\xf8\n\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TronAddress\x10\xf9\n\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_TronSignTx\x10\xfa\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_TronSignedTx\x10\xfb\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_TronSignMessage\x10\xfc\n\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TronMessageSignature\x10\xfd\n\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_TronVerifyMessage\x10\xfe\n\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TronSignTypedHash\x10\xff\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_TronTypedDataSignature\x10\x80\x0b\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_TonGetAddress\x10\xdc\x0b\x1a\x04\x90\xb5\x18\x01\x12!\n\x16MessageType_TonAddress\x10\xdd\x0b\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_TonSignTx\x10\xde\x0b\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TonSignedTx\x10\xdf\x0b\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TonSignMessage\x10\xe0\x0b\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_TonMessageSignature\x10\xe1\x0b\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_HiveGetPublicKey\x10\xc0\x0c\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_HivePublicKey\x10\xc1\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_HiveSignTx\x10\xc2\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_HiveSignedTx\x10\xc3\x0c\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_HiveGetPublicKeys\x10\xc4\x0c\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_HivePublicKeys\x10\xc5\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountCreate\x10\xc6\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountCreate\x10\xc7\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountUpdate\x10\xc8\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountUpdate\x10\xc9\x0c\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NearGetAddress\x10\xca\x0c\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NearAddress\x10\xcb\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NearSignTx\x10\xcc\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NearSignedTx\x10\xcd\x0c\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_HiveSignMessage\x10\xce\x0c\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_HiveSignedMessage\x10\xcf\x0c\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_HiveSignOperations\x10\xd0\x0c\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_HiveSignedOperations\x10\xd1\x0c\x1a\x04\x98\xb5\x18\x01\x12\x34\n)MessageType_ClearsignAttestorGetPublicKey\x10\xa4\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorPublicKey\x10\xa5\r\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ClearsignAttestorSign\x10\xa6\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorSignature\x10\xa7\r\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') + , + dependencies=[types__pb2.DESCRIPTOR,]) + +_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='MessageType_Initialize', index=0, number=0, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Ping', index=1, number=1, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Success', index=2, number=2, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Failure', index=3, number=3, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ChangePin', index=4, number=4, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_WipeDevice', index=5, number=5, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_FirmwareErase', index=6, number=6, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_FirmwareUpload', index=7, number=7, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetEntropy', index=8, number=9, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Entropy', index=9, number=10, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetPublicKey', index=10, number=11, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_PublicKey', index=11, number=12, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_LoadDevice', index=12, number=13, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ResetDevice', index=13, number=14, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SignTx', index=14, number=15, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Features', index=15, number=17, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_PinMatrixRequest', index=16, number=18, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_PinMatrixAck', index=17, number=19, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Cancel', index=18, number=20, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TxRequest', index=19, number=21, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TxAck', index=20, number=22, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CipherKeyValue', index=21, number=23, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ClearSession', index=22, number=24, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ApplySettings', index=23, number=25, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ButtonRequest', index=24, number=26, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ButtonAck', index=25, number=27, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetAddress', index=26, number=29, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Address', index=27, number=30, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EntropyRequest', index=28, number=35, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EntropyAck', index=29, number=36, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SignMessage', index=30, number=38, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_VerifyMessage', index=31, number=39, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MessageSignature', index=32, number=40, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_PassphraseRequest', index=33, number=41, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_PassphraseAck', index=34, number=42, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RecoveryDevice', index=35, number=45, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_WordRequest', index=36, number=46, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_WordAck', index=37, number=47, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CipheredKeyValue', index=38, number=48, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EncryptMessage', index=39, number=49, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EncryptedMessage', index=40, number=50, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DecryptMessage', index=41, number=51, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DecryptedMessage', index=42, number=52, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SignIdentity', index=43, number=53, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SignedIdentity', index=44, number=54, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetFeatures', index=45, number=55, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumGetAddress', index=46, number=56, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumAddress', index=47, number=57, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumSignTx', index=48, number=58, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTxRequest', index=49, number=59, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTxAck', index=50, number=60, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CharacterRequest', index=51, number=80, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CharacterAck', index=52, number=81, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RawTxAck', index=53, number=82, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ApplyPolicies', index=54, number=83, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_FlashHash', index=55, number=84, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_FlashWrite', index=56, number=85, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_FlashHashResponse', index=57, number=86, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkFlashDump', index=58, number=87, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkFlashDumpResponse', index=59, number=88, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SoftReset', index=60, number=89, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkDecision', index=61, number=100, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkGetState', index=62, number=101, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkState', index=63, number=102, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkStop', index=64, number=103, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkLog', index=65, number=104, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_DebugLinkFillConfig', index=66, number=105, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetCoinTable', index=67, number=106, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CoinTable', index=68, number=107, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumSignMessage', index=69, number=108, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumVerifyMessage', index=70, number=109, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumMessageSignature', index=71, number=110, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ChangeWipeCode', index=72, number=111, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumSignTypedHash', index=73, number=112, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTypedDataSignature', index=74, number=113, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Ethereum712TypesValues', index=75, number=114, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTxMetadata', index=76, number=115, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumMetadataAck', index=77, number=116, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_LoadClearsignSigner', index=78, number=117, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumSignTypedData', index=79, number=1704, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTypedDataStructRequest', index=80, number=1705, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTypedDataStructAck', index=81, number=1706, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTypedDataValueRequest', index=82, number=1707, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumTypedDataValueAck', index=83, number=1708, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumClearSignDefinition', index=84, number=1709, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumClearSignDefinitionAck', index=85, number=1710, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumClearSignDefinitionRequest', index=86, number=1711, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EthereumClearSignDefinitionChunk', index=87, number=1712, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_GetBip85Mnemonic', index=88, number=120, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_Bip85Mnemonic', index=89, number=121, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RippleGetAddress', index=90, number=400, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RippleAddress', index=91, number=401, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RippleSignTx', index=92, number=402, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_RippleSignedTx', index=93, number=403, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainGetAddress', index=94, number=500, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainAddress', index=95, number=501, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainSignTx', index=96, number=502, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainMsgRequest', index=97, number=503, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainMsgAck', index=98, number=504, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ThorchainSignedTx', index=99, number=505, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosGetPublicKey', index=100, number=600, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosPublicKey', index=101, number=601, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosSignTx', index=102, number=602, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosTxActionRequest', index=103, number=603, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosTxActionAck', index=104, number=604, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_EosSignedTx', index=105, number=605, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NanoGetAddress', index=106, number=700, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NanoAddress', index=107, number=701, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NanoSignTx', index=108, number=702, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NanoSignedTx', index=109, number=703, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaGetAddress', index=110, number=750, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaAddress', index=111, number=751, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaSignTx', index=112, number=752, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaSignedTx', index=113, number=753, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaSignMessage', index=114, number=754, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaMessageSignature', index=115, number=755, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaSignOffchainMessage', index=116, number=756, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_SolanaOffchainMessageSignature', index=117, number=757, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceGetAddress', index=118, number=800, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceAddress', index=119, number=801, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceGetPublicKey', index=120, number=802, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinancePublicKey', index=121, number=803, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceSignTx', index=122, number=804, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceTxRequest', index=123, number=805, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceTransferMsg', index=124, number=806, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceOrderMsg', index=125, number=807, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceCancelMsg', index=126, number=808, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_BinanceSignedTx', index=127, number=809, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosGetAddress', index=128, number=900, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosAddress', index=129, number=901, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosSignTx', index=130, number=902, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgRequest', index=131, number=903, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgAck', index=132, number=904, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosSignedTx', index=133, number=905, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgDelegate', index=134, number=906, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgUndelegate', index=135, number=907, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgRedelegate', index=136, number=908, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgRewards', index=137, number=909, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_CosmosMsgIBCTransfer', index=138, number=910, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintGetAddress', index=139, number=1000, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintAddress', index=140, number=1001, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintSignTx', index=141, number=1002, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgRequest', index=142, number=1003, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgAck', index=143, number=1004, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgSend', index=144, number=1005, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintSignedTx', index=145, number=1006, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgDelegate', index=146, number=1007, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgUndelegate', index=147, number=1008, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgRedelegate', index=148, number=1009, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgRewards', index=149, number=1010, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TendermintMsgIBCTransfer', index=150, number=1011, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisGetAddress', index=151, number=1100, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisAddress', index=152, number=1101, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisSignTx', index=153, number=1102, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgRequest', index=154, number=1103, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgAck', index=155, number=1104, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgSend', index=156, number=1105, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgDelegate', index=157, number=1106, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgUndelegate', index=158, number=1107, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgRedelegate', index=159, number=1108, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgRewards', index=160, number=1109, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgLPAdd', index=161, number=1110, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgLPRemove', index=162, number=1111, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgLPStake', index=163, number=1112, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgLPUnstake', index=164, number=1113, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgIBCTransfer', index=165, number=1114, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisMsgSwap', index=166, number=1115, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_OsmosisSignedTx', index=167, number=1116, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainGetAddress', index=168, number=1200, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainAddress', index=169, number=1201, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainSignTx', index=170, number=1202, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainMsgRequest', index=171, number=1203, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainMsgAck', index=172, number=1204, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_MayachainSignedTx', index=173, number=1205, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashSignPCZT', index=174, number=1300, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashPCZTAction', index=175, number=1301, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashPCZTActionAck', index=176, number=1302, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashSignedPCZT', index=177, number=1303, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashGetOrchardFVK', index=178, number=1304, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashOrchardFVK', index=179, number=1305, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashTransparentInput', index=180, number=1306, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashTransparentSigned', index=181, number=1307, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashDisplayAddress', index=182, number=1308, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashAddress', index=183, number=1309, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashTransparentOutput', index=184, number=1310, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ZcashTransparentAck', index=185, number=1311, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronGetAddress', index=186, number=1400, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronAddress', index=187, number=1401, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignTx', index=188, number=1402, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignedTx', index=189, number=1403, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignMessage', index=190, number=1404, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronMessageSignature', index=191, number=1405, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronVerifyMessage', index=192, number=1406, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronSignTypedHash', index=193, number=1407, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TronTypedDataSignature', index=194, number=1408, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonGetAddress', index=195, number=1500, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonAddress', index=196, number=1501, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonSignTx', index=197, number=1502, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonSignedTx', index=198, number=1503, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonSignMessage', index=199, number=1504, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_TonMessageSignature', index=200, number=1505, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveGetPublicKey', index=201, number=1600, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HivePublicKey', index=202, number=1601, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignTx', index=203, number=1602, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignedTx', index=204, number=1603, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveGetPublicKeys', index=205, number=1604, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HivePublicKeys', index=206, number=1605, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignAccountCreate', index=207, number=1606, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignedAccountCreate', index=208, number=1607, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignAccountUpdate', index=209, number=1608, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignedAccountUpdate', index=210, number=1609, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NearGetAddress', index=211, number=1610, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NearAddress', index=212, number=1611, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NearSignTx', index=213, number=1612, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_NearSignedTx', index=214, number=1613, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignMessage', index=215, number=1614, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignedMessage', index=216, number=1615, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignOperations', index=217, number=1616, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_HiveSignedOperations', index=218, number=1617, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ClearsignAttestorGetPublicKey', index=219, number=1700, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ClearsignAttestorPublicKey', index=220, number=1701, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ClearsignAttestorSign', index=221, number=1702, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')), + type=None), + _descriptor.EnumValueDescriptor( + name='MessageType_ClearsignAttestorSignature', index=222, number=1703, + options=_descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')), + type=None), + ], + containing_type=None, + options=None, + serialized_start=5517, + serialized_end=14544, +) +_sym_db.RegisterEnumDescriptor(_MESSAGETYPE) + +MessageType = enum_type_wrapper.EnumTypeWrapper(_MESSAGETYPE) +MessageType_Initialize = 0 +MessageType_Ping = 1 +MessageType_Success = 2 +MessageType_Failure = 3 +MessageType_ChangePin = 4 +MessageType_WipeDevice = 5 +MessageType_FirmwareErase = 6 +MessageType_FirmwareUpload = 7 +MessageType_GetEntropy = 9 +MessageType_Entropy = 10 +MessageType_GetPublicKey = 11 +MessageType_PublicKey = 12 +MessageType_LoadDevice = 13 +MessageType_ResetDevice = 14 +MessageType_SignTx = 15 +MessageType_Features = 17 +MessageType_PinMatrixRequest = 18 +MessageType_PinMatrixAck = 19 +MessageType_Cancel = 20 +MessageType_TxRequest = 21 +MessageType_TxAck = 22 +MessageType_CipherKeyValue = 23 +MessageType_ClearSession = 24 +MessageType_ApplySettings = 25 +MessageType_ButtonRequest = 26 +MessageType_ButtonAck = 27 +MessageType_GetAddress = 29 +MessageType_Address = 30 +MessageType_EntropyRequest = 35 +MessageType_EntropyAck = 36 +MessageType_SignMessage = 38 +MessageType_VerifyMessage = 39 +MessageType_MessageSignature = 40 +MessageType_PassphraseRequest = 41 +MessageType_PassphraseAck = 42 +MessageType_RecoveryDevice = 45 +MessageType_WordRequest = 46 +MessageType_WordAck = 47 +MessageType_CipheredKeyValue = 48 +MessageType_EncryptMessage = 49 +MessageType_EncryptedMessage = 50 +MessageType_DecryptMessage = 51 +MessageType_DecryptedMessage = 52 +MessageType_SignIdentity = 53 +MessageType_SignedIdentity = 54 +MessageType_GetFeatures = 55 +MessageType_EthereumGetAddress = 56 +MessageType_EthereumAddress = 57 +MessageType_EthereumSignTx = 58 +MessageType_EthereumTxRequest = 59 +MessageType_EthereumTxAck = 60 +MessageType_CharacterRequest = 80 +MessageType_CharacterAck = 81 +MessageType_RawTxAck = 82 +MessageType_ApplyPolicies = 83 +MessageType_FlashHash = 84 +MessageType_FlashWrite = 85 +MessageType_FlashHashResponse = 86 +MessageType_DebugLinkFlashDump = 87 +MessageType_DebugLinkFlashDumpResponse = 88 +MessageType_SoftReset = 89 +MessageType_DebugLinkDecision = 100 +MessageType_DebugLinkGetState = 101 +MessageType_DebugLinkState = 102 +MessageType_DebugLinkStop = 103 +MessageType_DebugLinkLog = 104 +MessageType_DebugLinkFillConfig = 105 +MessageType_GetCoinTable = 106 +MessageType_CoinTable = 107 +MessageType_EthereumSignMessage = 108 +MessageType_EthereumVerifyMessage = 109 +MessageType_EthereumMessageSignature = 110 +MessageType_ChangeWipeCode = 111 +MessageType_EthereumSignTypedHash = 112 +MessageType_EthereumTypedDataSignature = 113 +MessageType_Ethereum712TypesValues = 114 +MessageType_EthereumTxMetadata = 115 +MessageType_EthereumMetadataAck = 116 +MessageType_LoadClearsignSigner = 117 +MessageType_EthereumSignTypedData = 1704 +MessageType_EthereumTypedDataStructRequest = 1705 +MessageType_EthereumTypedDataStructAck = 1706 +MessageType_EthereumTypedDataValueRequest = 1707 +MessageType_EthereumTypedDataValueAck = 1708 +MessageType_EthereumClearSignDefinition = 1709 +MessageType_EthereumClearSignDefinitionAck = 1710 +MessageType_EthereumClearSignDefinitionRequest = 1711 +MessageType_EthereumClearSignDefinitionChunk = 1712 +MessageType_GetBip85Mnemonic = 120 +MessageType_Bip85Mnemonic = 121 +MessageType_RippleGetAddress = 400 +MessageType_RippleAddress = 401 +MessageType_RippleSignTx = 402 +MessageType_RippleSignedTx = 403 +MessageType_ThorchainGetAddress = 500 +MessageType_ThorchainAddress = 501 +MessageType_ThorchainSignTx = 502 +MessageType_ThorchainMsgRequest = 503 +MessageType_ThorchainMsgAck = 504 +MessageType_ThorchainSignedTx = 505 +MessageType_EosGetPublicKey = 600 +MessageType_EosPublicKey = 601 +MessageType_EosSignTx = 602 +MessageType_EosTxActionRequest = 603 +MessageType_EosTxActionAck = 604 +MessageType_EosSignedTx = 605 +MessageType_NanoGetAddress = 700 +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_SolanaSignOffchainMessage = 756 +MessageType_SolanaOffchainMessageSignature = 757 +MessageType_BinanceGetAddress = 800 +MessageType_BinanceAddress = 801 +MessageType_BinanceGetPublicKey = 802 +MessageType_BinancePublicKey = 803 +MessageType_BinanceSignTx = 804 +MessageType_BinanceTxRequest = 805 +MessageType_BinanceTransferMsg = 806 +MessageType_BinanceOrderMsg = 807 +MessageType_BinanceCancelMsg = 808 +MessageType_BinanceSignedTx = 809 +MessageType_CosmosGetAddress = 900 +MessageType_CosmosAddress = 901 +MessageType_CosmosSignTx = 902 +MessageType_CosmosMsgRequest = 903 +MessageType_CosmosMsgAck = 904 +MessageType_CosmosSignedTx = 905 +MessageType_CosmosMsgDelegate = 906 +MessageType_CosmosMsgUndelegate = 907 +MessageType_CosmosMsgRedelegate = 908 +MessageType_CosmosMsgRewards = 909 +MessageType_CosmosMsgIBCTransfer = 910 +MessageType_TendermintGetAddress = 1000 +MessageType_TendermintAddress = 1001 +MessageType_TendermintSignTx = 1002 +MessageType_TendermintMsgRequest = 1003 +MessageType_TendermintMsgAck = 1004 +MessageType_TendermintMsgSend = 1005 +MessageType_TendermintSignedTx = 1006 +MessageType_TendermintMsgDelegate = 1007 +MessageType_TendermintMsgUndelegate = 1008 +MessageType_TendermintMsgRedelegate = 1009 +MessageType_TendermintMsgRewards = 1010 +MessageType_TendermintMsgIBCTransfer = 1011 +MessageType_OsmosisGetAddress = 1100 +MessageType_OsmosisAddress = 1101 +MessageType_OsmosisSignTx = 1102 +MessageType_OsmosisMsgRequest = 1103 +MessageType_OsmosisMsgAck = 1104 +MessageType_OsmosisMsgSend = 1105 +MessageType_OsmosisMsgDelegate = 1106 +MessageType_OsmosisMsgUndelegate = 1107 +MessageType_OsmosisMsgRedelegate = 1108 +MessageType_OsmosisMsgRewards = 1109 +MessageType_OsmosisMsgLPAdd = 1110 +MessageType_OsmosisMsgLPRemove = 1111 +MessageType_OsmosisMsgLPStake = 1112 +MessageType_OsmosisMsgLPUnstake = 1113 +MessageType_OsmosisMsgIBCTransfer = 1114 +MessageType_OsmosisMsgSwap = 1115 +MessageType_OsmosisSignedTx = 1116 +MessageType_MayachainGetAddress = 1200 +MessageType_MayachainAddress = 1201 +MessageType_MayachainSignTx = 1202 +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 +MessageType_ZcashTransparentInput = 1306 +MessageType_ZcashTransparentSigned = 1307 +MessageType_ZcashDisplayAddress = 1308 +MessageType_ZcashAddress = 1309 +MessageType_ZcashTransparentOutput = 1310 +MessageType_ZcashTransparentAck = 1311 +MessageType_TronGetAddress = 1400 +MessageType_TronAddress = 1401 +MessageType_TronSignTx = 1402 +MessageType_TronSignedTx = 1403 +MessageType_TronSignMessage = 1404 +MessageType_TronMessageSignature = 1405 +MessageType_TronVerifyMessage = 1406 +MessageType_TronSignTypedHash = 1407 +MessageType_TronTypedDataSignature = 1408 +MessageType_TonGetAddress = 1500 +MessageType_TonAddress = 1501 +MessageType_TonSignTx = 1502 +MessageType_TonSignedTx = 1503 +MessageType_TonSignMessage = 1504 +MessageType_TonMessageSignature = 1505 +MessageType_HiveGetPublicKey = 1600 +MessageType_HivePublicKey = 1601 +MessageType_HiveSignTx = 1602 +MessageType_HiveSignedTx = 1603 +MessageType_HiveGetPublicKeys = 1604 +MessageType_HivePublicKeys = 1605 +MessageType_HiveSignAccountCreate = 1606 +MessageType_HiveSignedAccountCreate = 1607 +MessageType_HiveSignAccountUpdate = 1608 +MessageType_HiveSignedAccountUpdate = 1609 +MessageType_NearGetAddress = 1610 +MessageType_NearAddress = 1611 +MessageType_NearSignTx = 1612 +MessageType_NearSignedTx = 1613 +MessageType_HiveSignMessage = 1614 +MessageType_HiveSignedMessage = 1615 +MessageType_HiveSignOperations = 1616 +MessageType_HiveSignedOperations = 1617 +MessageType_ClearsignAttestorGetPublicKey = 1700 +MessageType_ClearsignAttestorPublicKey = 1701 +MessageType_ClearsignAttestorSign = 1702 +MessageType_ClearsignAttestorSignature = 1703 + + + +_INITIALIZE = _descriptor.Descriptor( + name='Initialize', + full_name='Initialize', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=31, + serialized_end=43, +) + + +_GETFEATURES = _descriptor.Descriptor( + name='GetFeatures', + full_name='GetFeatures', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=45, + serialized_end=58, +) + + +_FEATURES = _descriptor.Descriptor( + name='Features', + full_name='Features', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='vendor', full_name='Features.vendor', 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), + _descriptor.FieldDescriptor( + name='major_version', full_name='Features.major_version', 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='minor_version', full_name='Features.minor_version', index=2, + number=3, 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='patch_version', full_name='Features.patch_version', 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='bootloader_mode', full_name='Features.bootloader_mode', index=4, + number=5, 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='device_id', full_name='Features.device_id', index=5, + number=6, 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), + _descriptor.FieldDescriptor( + name='pin_protection', full_name='Features.pin_protection', index=6, + number=7, 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='passphrase_protection', full_name='Features.passphrase_protection', index=7, + number=8, 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='language', full_name='Features.language', index=8, + number=9, 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), + _descriptor.FieldDescriptor( + name='label', full_name='Features.label', index=9, + number=10, 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), + _descriptor.FieldDescriptor( + name='coins', full_name='Features.coins', index=10, + number=11, type=11, cpp_type=10, 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='initialized', full_name='Features.initialized', index=11, + number=12, 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='revision', full_name='Features.revision', 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='bootloader_hash', full_name='Features.bootloader_hash', 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), + _descriptor.FieldDescriptor( + name='imported', full_name='Features.imported', index=14, + number=15, 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='pin_cached', full_name='Features.pin_cached', index=15, + number=16, 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='passphrase_cached', full_name='Features.passphrase_cached', index=16, + number=17, 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='policies', full_name='Features.policies', index=17, + number=18, type=11, cpp_type=10, 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='model', full_name='Features.model', index=18, + number=21, 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), + _descriptor.FieldDescriptor( + name='firmware_variant', full_name='Features.firmware_variant', index=19, + number=22, 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), + _descriptor.FieldDescriptor( + name='firmware_hash', full_name='Features.firmware_hash', index=20, + number=23, 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='no_backup', full_name='Features.no_backup', index=21, + number=24, 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='wipe_code_protection', full_name='Features.wipe_code_protection', index=22, + number=25, 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='auto_lock_delay_ms', full_name='Features.auto_lock_delay_ms', index=23, + number=26, 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='supports_taproot', full_name='Features.supports_taproot', index=24, + number=27, 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='supports_dice_modes', full_name='Features.supports_dice_modes', index=25, + number=28, 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=61, + serialized_end=670, +) + + +_GETCOINTABLE = _descriptor.Descriptor( + name='GetCoinTable', + full_name='GetCoinTable', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start', full_name='GetCoinTable.start', 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='end', full_name='GetCoinTable.end', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=672, + serialized_end=714, +) + + +_COINTABLE = _descriptor.Descriptor( + name='CoinTable', + full_name='CoinTable', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='table', full_name='CoinTable.table', index=0, + number=1, type=11, cpp_type=10, 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='num_coins', full_name='CoinTable.num_coins', 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='chunk_size', full_name='CoinTable.chunk_size', index=2, + number=3, 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=716, + serialized_end=792, +) + + +_CLEARSESSION = _descriptor.Descriptor( + name='ClearSession', + full_name='ClearSession', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=794, + serialized_end=808, +) + + +_APPLYSETTINGS = _descriptor.Descriptor( + name='ApplySettings', + full_name='ApplySettings', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='language', full_name='ApplySettings.language', 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), + _descriptor.FieldDescriptor( + name='label', full_name='ApplySettings.label', index=1, + number=2, 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), + _descriptor.FieldDescriptor( + name='use_passphrase', full_name='ApplySettings.use_passphrase', 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), + _descriptor.FieldDescriptor( + name='auto_lock_delay_ms', full_name='ApplySettings.auto_lock_delay_ms', 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='u2f_counter', full_name='ApplySettings.u2f_counter', index=4, + number=5, 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=810, + serialized_end=931, +) + + +_CHANGEPIN = _descriptor.Descriptor( + name='ChangePin', + full_name='ChangePin', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='remove', full_name='ChangePin.remove', index=0, + number=1, 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=933, + serialized_end=960, +) + + +_PING = _descriptor.Descriptor( + name='Ping', + full_name='Ping', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='Ping.message', 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), + _descriptor.FieldDescriptor( + name='button_protection', full_name='Ping.button_protection', index=1, + number=2, 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='pin_protection', full_name='Ping.pin_protection', 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), + _descriptor.FieldDescriptor( + name='passphrase_protection', full_name='Ping.passphrase_protection', index=3, + number=4, 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='wipe_code_protection', full_name='Ping.wipe_code_protection', index=4, + number=5, 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=963, + serialized_end=1098, +) + + +_SUCCESS = _descriptor.Descriptor( + name='Success', + full_name='Success', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='Success.message', 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=1100, + serialized_end=1126, +) + + +_FAILURE = _descriptor.Descriptor( + name='Failure', + full_name='Failure', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='code', full_name='Failure.code', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + 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='Failure.message', index=1, + number=2, 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=1128, + serialized_end=1182, +) + + +_BUTTONREQUEST = _descriptor.Descriptor( + name='ButtonRequest', + full_name='ButtonRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='code', full_name='ButtonRequest.code', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='data', full_name='ButtonRequest.data', index=1, + number=2, 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=1184, + serialized_end=1247, +) + + +_BUTTONACK = _descriptor.Descriptor( + name='ButtonAck', + full_name='ButtonAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1249, + serialized_end=1260, +) + + +_PINMATRIXREQUEST = _descriptor.Descriptor( + name='PinMatrixRequest', + full_name='PinMatrixRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='PinMatrixRequest.type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=1, + 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=1262, + serialized_end=1317, +) + + +_PINMATRIXACK = _descriptor.Descriptor( + name='PinMatrixAck', + full_name='PinMatrixAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='pin', full_name='PinMatrixAck.pin', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=1319, + serialized_end=1346, +) + + +_CANCEL = _descriptor.Descriptor( + name='Cancel', + full_name='Cancel', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1348, + serialized_end=1356, +) + + +_PASSPHRASEREQUEST = _descriptor.Descriptor( + name='PassphraseRequest', + full_name='PassphraseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1358, + serialized_end=1377, +) + + +_PASSPHRASEACK = _descriptor.Descriptor( + name='PassphraseAck', + full_name='PassphraseAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='passphrase', full_name='PassphraseAck.passphrase', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=1379, + serialized_end=1414, +) + + +_GETENTROPY = _descriptor.Descriptor( + name='GetEntropy', + full_name='GetEntropy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='size', full_name='GetEntropy.size', index=0, + number=1, type=13, cpp_type=3, label=2, + 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=1416, + serialized_end=1442, +) + + +_ENTROPY = _descriptor.Descriptor( + name='Entropy', + full_name='Entropy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='entropy', full_name='Entropy.entropy', index=0, + number=1, type=12, cpp_type=9, label=2, + 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=1444, + serialized_end=1470, +) + + +_GETPUBLICKEY = _descriptor.Descriptor( + name='GetPublicKey', + full_name='GetPublicKey', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='GetPublicKey.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='ecdsa_curve_name', full_name='GetPublicKey.ecdsa_curve_name', index=1, + number=2, 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), + _descriptor.FieldDescriptor( + name='show_display', full_name='GetPublicKey.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), + _descriptor.FieldDescriptor( + name='coin_name', full_name='GetPublicKey.coin_name', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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='script_type', full_name='GetPublicKey.script_type', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=True, 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=1473, + serialized_end=1635, +) + + +_PUBLICKEY = _descriptor.Descriptor( + name='PublicKey', + full_name='PublicKey', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='node', full_name='PublicKey.node', index=0, + number=1, type=11, cpp_type=10, label=2, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='xpub', full_name='PublicKey.xpub', index=1, + number=2, 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=1637, + serialized_end=1689, +) + + +_GETADDRESS = _descriptor.Descriptor( + name='GetAddress', + full_name='GetAddress', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='GetAddress.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='GetAddress.coin_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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='GetAddress.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), + _descriptor.FieldDescriptor( + name='multisig', full_name='GetAddress.multisig', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='script_type', full_name='GetAddress.script_type', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=True, 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=1692, + serialized_end=1871, +) + + +_ADDRESS = _descriptor.Descriptor( + name='Address', + full_name='Address', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='Address.address', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=1873, + serialized_end=1899, +) + + +_WIPEDEVICE = _descriptor.Descriptor( + name='WipeDevice', + full_name='WipeDevice', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1901, + serialized_end=1913, +) + + +_LOADDEVICE = _descriptor.Descriptor( + name='LoadDevice', + full_name='LoadDevice', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='mnemonic', full_name='LoadDevice.mnemonic', 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), + _descriptor.FieldDescriptor( + name='node', full_name='LoadDevice.node', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='pin', full_name='LoadDevice.pin', index=2, + number=3, 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), + _descriptor.FieldDescriptor( + name='passphrase_protection', full_name='LoadDevice.passphrase_protection', index=3, + number=4, 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='language', full_name='LoadDevice.language', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("english").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='label', full_name='LoadDevice.label', index=5, + number=6, 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), + _descriptor.FieldDescriptor( + name='skip_checksum', full_name='LoadDevice.skip_checksum', index=6, + number=7, 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='u2f_counter', full_name='LoadDevice.u2f_counter', index=7, + number=8, 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=1916, + serialized_end=2103, +) + + +_RESETDEVICE = _descriptor.Descriptor( + name='ResetDevice', + full_name='ResetDevice', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='display_random', full_name='ResetDevice.display_random', index=0, + number=1, 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='strength', full_name='ResetDevice.strength', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=True, default_value=256, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='passphrase_protection', full_name='ResetDevice.passphrase_protection', 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), + _descriptor.FieldDescriptor( + name='pin_protection', full_name='ResetDevice.pin_protection', index=3, + number=4, 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='language', full_name='ResetDevice.language', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("english").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='label', full_name='ResetDevice.label', index=5, + number=6, 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), + _descriptor.FieldDescriptor( + name='no_backup', full_name='ResetDevice.no_backup', index=6, + number=7, 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='auto_lock_delay_ms', full_name='ResetDevice.auto_lock_delay_ms', index=7, + number=8, 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='u2f_counter', full_name='ResetDevice.u2f_counter', index=8, + number=9, 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='dice_entropy', full_name='ResetDevice.dice_entropy', index=9, + number=10, 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='dice_only', full_name='ResetDevice.dice_only', index=10, + number=11, 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=2106, + serialized_end=2372, +) + + +_ENTROPYREQUEST = _descriptor.Descriptor( + name='EntropyRequest', + full_name='EntropyRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2374, + serialized_end=2390, +) + + +_ENTROPYACK = _descriptor.Descriptor( + name='EntropyAck', + full_name='EntropyAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='entropy', full_name='EntropyAck.entropy', 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=2392, + serialized_end=2421, +) + + +_RECOVERYDEVICE = _descriptor.Descriptor( + name='RecoveryDevice', + full_name='RecoveryDevice', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='word_count', full_name='RecoveryDevice.word_count', 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='passphrase_protection', full_name='RecoveryDevice.passphrase_protection', index=1, + number=2, 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='pin_protection', full_name='RecoveryDevice.pin_protection', 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), + _descriptor.FieldDescriptor( + name='language', full_name='RecoveryDevice.language', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("english").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='label', full_name='RecoveryDevice.label', index=4, + number=5, 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), + _descriptor.FieldDescriptor( + name='enforce_wordlist', full_name='RecoveryDevice.enforce_wordlist', 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='use_character_cipher', full_name='RecoveryDevice.use_character_cipher', index=6, + number=7, 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='auto_lock_delay_ms', full_name='RecoveryDevice.auto_lock_delay_ms', index=7, + number=8, 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='u2f_counter', full_name='RecoveryDevice.u2f_counter', index=8, + number=9, 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='dry_run', full_name='RecoveryDevice.dry_run', index=9, + number=10, 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=2424, + serialized_end=2679, +) + + +_WORDREQUEST = _descriptor.Descriptor( + name='WordRequest', + full_name='WordRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2681, + serialized_end=2694, +) + + +_WORDACK = _descriptor.Descriptor( + name='WordAck', + full_name='WordAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='word', full_name='WordAck.word', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=2696, + serialized_end=2719, +) + + +_CHARACTERREQUEST = _descriptor.Descriptor( + name='CharacterRequest', + full_name='CharacterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='word_pos', full_name='CharacterRequest.word_pos', index=0, + number=1, type=13, cpp_type=3, label=2, + 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='character_pos', full_name='CharacterRequest.character_pos', index=1, + number=2, type=13, cpp_type=3, label=2, + 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=2721, + serialized_end=2780, +) + + +_CHARACTERACK = _descriptor.Descriptor( + name='CharacterAck', + full_name='CharacterAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='character', full_name='CharacterAck.character', 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), + _descriptor.FieldDescriptor( + name='delete', full_name='CharacterAck.delete', index=1, + number=2, 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='done', full_name='CharacterAck.done', 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=2782, + serialized_end=2845, +) + + +_SIGNMESSAGE = _descriptor.Descriptor( + name='SignMessage', + full_name='SignMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='SignMessage.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='message', full_name='SignMessage.message', index=1, + number=2, type=12, cpp_type=9, label=2, + 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='coin_name', full_name='SignMessage.coin_name', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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='script_type', full_name='SignMessage.script_type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=True, 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=2848, + serialized_end=2978, +) + + +_VERIFYMESSAGE = _descriptor.Descriptor( + name='VerifyMessage', + full_name='VerifyMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='VerifyMessage.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), + _descriptor.FieldDescriptor( + name='signature', full_name='VerifyMessage.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), + _descriptor.FieldDescriptor( + name='message', full_name='VerifyMessage.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='coin_name', full_name='VerifyMessage.coin_name', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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=2980, + serialized_end=3076, +) + + +_MESSAGESIGNATURE = _descriptor.Descriptor( + name='MessageSignature', + full_name='MessageSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='MessageSignature.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), + _descriptor.FieldDescriptor( + name='signature', full_name='MessageSignature.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=3078, + serialized_end=3132, +) + + +_ENCRYPTMESSAGE = _descriptor.Descriptor( + name='EncryptMessage', + full_name='EncryptMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='pubkey', full_name='EncryptMessage.pubkey', 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='message', full_name='EncryptMessage.message', 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='display_only', full_name='EncryptMessage.display_only', 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), + _descriptor.FieldDescriptor( + name='address_n', full_name='EncryptMessage.address_n', index=3, + number=4, 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='EncryptMessage.coin_name', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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=3134, + serialized_end=3252, +) + + +_ENCRYPTEDMESSAGE = _descriptor.Descriptor( + name='EncryptedMessage', + full_name='EncryptedMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='nonce', full_name='EncryptedMessage.nonce', 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='message', full_name='EncryptedMessage.message', 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='hmac', full_name='EncryptedMessage.hmac', 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=3254, + serialized_end=3318, +) + + +_DECRYPTMESSAGE = _descriptor.Descriptor( + name='DecryptMessage', + full_name='DecryptMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='DecryptMessage.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='nonce', full_name='DecryptMessage.nonce', 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='message', full_name='DecryptMessage.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='hmac', full_name='DecryptMessage.hmac', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3320, + serialized_end=3401, +) + + +_DECRYPTEDMESSAGE = _descriptor.Descriptor( + name='DecryptedMessage', + full_name='DecryptedMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='DecryptedMessage.message', 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='address', full_name='DecryptedMessage.address', index=1, + number=2, 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=3403, + serialized_end=3455, +) + + +_CIPHERKEYVALUE = _descriptor.Descriptor( + name='CipherKeyValue', + full_name='CipherKeyValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address_n', full_name='CipherKeyValue.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='key', full_name='CipherKeyValue.key', index=1, + number=2, 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), + _descriptor.FieldDescriptor( + name='value', full_name='CipherKeyValue.value', 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='encrypt', full_name='CipherKeyValue.encrypt', index=3, + number=4, 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='ask_on_encrypt', full_name='CipherKeyValue.ask_on_encrypt', index=4, + number=5, 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='ask_on_decrypt', full_name='CipherKeyValue.ask_on_decrypt', 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='iv', full_name='CipherKeyValue.iv', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3458, + serialized_end=3598, +) + + +_CIPHEREDKEYVALUE = _descriptor.Descriptor( + name='CipheredKeyValue', + full_name='CipheredKeyValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='CipheredKeyValue.value', 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=3600, + serialized_end=3633, +) + + +_GETBIP85MNEMONIC = _descriptor.Descriptor( + name='GetBip85Mnemonic', + full_name='GetBip85Mnemonic', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='word_count', full_name='GetBip85Mnemonic.word_count', index=0, + number=1, type=13, cpp_type=3, label=2, + 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='index', full_name='GetBip85Mnemonic.index', index=1, + number=2, type=13, cpp_type=3, label=2, + 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=3635, + serialized_end=3688, +) + + +_BIP85MNEMONIC = _descriptor.Descriptor( + name='Bip85Mnemonic', + full_name='Bip85Mnemonic', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='mnemonic', full_name='Bip85Mnemonic.mnemonic', index=0, + number=1, type=9, cpp_type=9, label=2, + 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=3690, + serialized_end=3723, +) + + +_SIGNTX = _descriptor.Descriptor( + name='SignTx', + full_name='SignTx', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='outputs_count', full_name='SignTx.outputs_count', index=0, + number=1, type=13, cpp_type=3, label=2, + 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='inputs_count', full_name='SignTx.inputs_count', index=1, + number=2, type=13, cpp_type=3, label=2, + 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='coin_name', full_name='SignTx.coin_name', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=True, default_value=_b("Bitcoin").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='version', full_name='SignTx.version', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=True, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='lock_time', full_name='SignTx.lock_time', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=True, 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='expiry', full_name='SignTx.expiry', index=5, + number=6, 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='overwintered', full_name='SignTx.overwintered', index=6, + number=7, 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='version_group_id', full_name='SignTx.version_group_id', index=7, + number=8, 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='branch_id', full_name='SignTx.branch_id', index=8, + number=10, 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=3726, + serialized_end=3932, +) + + +_TXREQUEST = _descriptor.Descriptor( + name='TxRequest', + full_name='TxRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='request_type', full_name='TxRequest.request_type', index=0, + number=1, type=14, cpp_type=8, 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='details', full_name='TxRequest.details', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='serialized', full_name='TxRequest.serialized', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + 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=3935, + serialized_end=4068, +) + + +_TXACK = _descriptor.Descriptor( + name='TxAck', + full_name='TxAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='tx', full_name='TxAck.tx', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + 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=4070, + serialized_end=4107, +) + + +_RAWTXACK = _descriptor.Descriptor( + name='RawTxAck', + full_name='RawTxAck', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='tx', full_name='RawTxAck.tx', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + 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=4109, + serialized_end=4152, +) + + +_SIGNIDENTITY = _descriptor.Descriptor( + name='SignIdentity', + full_name='SignIdentity', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='identity', full_name='SignIdentity.identity', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='challenge_hidden', full_name='SignIdentity.challenge_hidden', 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='challenge_visual', full_name='SignIdentity.challenge_visual', index=2, + number=3, 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), + _descriptor.FieldDescriptor( + name='ecdsa_curve_name', full_name='SignIdentity.ecdsa_curve_name', index=3, + number=4, 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=4154, + serialized_end=4279, +) + + +_SIGNEDIDENTITY = _descriptor.Descriptor( + name='SignedIdentity', + full_name='SignedIdentity', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='SignedIdentity.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), + _descriptor.FieldDescriptor( + name='public_key', full_name='SignedIdentity.public_key', 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='signature', full_name='SignedIdentity.signature', 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=4281, + serialized_end=4353, +) + + +_APPLYPOLICIES = _descriptor.Descriptor( + name='ApplyPolicies', + full_name='ApplyPolicies', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='policy', full_name='ApplyPolicies.policy', index=0, + number=1, type=11, cpp_type=10, 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4355, + serialized_end=4399, +) + + +_FLASHHASH = _descriptor.Descriptor( + name='FlashHash', + full_name='FlashHash', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='FlashHash.address', 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='length', full_name='FlashHash.length', 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='challenge', full_name='FlashHash.challenge', 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=4401, + serialized_end=4464, +) + + +_FLASHWRITE = _descriptor.Descriptor( + name='FlashWrite', + full_name='FlashWrite', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='FlashWrite.address', 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='data', full_name='FlashWrite.data', 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='erase', full_name='FlashWrite.erase', 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=4466, + serialized_end=4524, +) + + +_FLASHHASHRESPONSE = _descriptor.Descriptor( + name='FlashHashResponse', + full_name='FlashHashResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='data', full_name='FlashHashResponse.data', 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=4526, + serialized_end=4559, +) + + +_DEBUGLINKFLASHDUMP = _descriptor.Descriptor( + name='DebugLinkFlashDump', + full_name='DebugLinkFlashDump', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='address', full_name='DebugLinkFlashDump.address', 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='length', full_name='DebugLinkFlashDump.length', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4561, + serialized_end=4614, +) + + +_DEBUGLINKFLASHDUMPRESPONSE = _descriptor.Descriptor( + name='DebugLinkFlashDumpResponse', + full_name='DebugLinkFlashDumpResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='data', full_name='DebugLinkFlashDumpResponse.data', 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=4616, + serialized_end=4658, +) + + +_SOFTRESET = _descriptor.Descriptor( + name='SoftReset', + full_name='SoftReset', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4660, + serialized_end=4671, +) + + +_FIRMWAREERASE = _descriptor.Descriptor( + name='FirmwareErase', + full_name='FirmwareErase', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4673, + serialized_end=4688, +) + + +_FIRMWAREUPLOAD = _descriptor.Descriptor( + name='FirmwareUpload', + full_name='FirmwareUpload', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='payload_hash', full_name='FirmwareUpload.payload_hash', index=0, + number=1, type=12, cpp_type=9, label=2, + 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='payload', full_name='FirmwareUpload.payload', index=1, + number=2, type=12, cpp_type=9, label=2, + 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=4690, + serialized_end=4745, +) + + +_DEBUGLINKDECISION = _descriptor.Descriptor( + name='DebugLinkDecision', + full_name='DebugLinkDecision', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='yes_no', full_name='DebugLinkDecision.yes_no', index=0, + number=1, type=8, cpp_type=7, label=2, + 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='input', full_name='DebugLinkDecision.input', index=1, + number=2, 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=4747, + serialized_end=4797, +) + + +_DEBUGLINKGETSTATE = _descriptor.Descriptor( + name='DebugLinkGetState', + full_name='DebugLinkGetState', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4799, + serialized_end=4818, +) + + +_DEBUGLINKSTATE = _descriptor.Descriptor( + name='DebugLinkState', + full_name='DebugLinkState', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='layout', full_name='DebugLinkState.layout', 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='pin', full_name='DebugLinkState.pin', index=1, + number=2, 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), + _descriptor.FieldDescriptor( + name='matrix', full_name='DebugLinkState.matrix', index=2, + number=3, 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), + _descriptor.FieldDescriptor( + name='mnemonic', full_name='DebugLinkState.mnemonic', index=3, + number=4, 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), + _descriptor.FieldDescriptor( + name='node', full_name='DebugLinkState.node', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='passphrase_protection', full_name='DebugLinkState.passphrase_protection', 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='reset_word', full_name='DebugLinkState.reset_word', index=6, + number=7, 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), + _descriptor.FieldDescriptor( + name='reset_entropy', full_name='DebugLinkState.reset_entropy', 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='recovery_fake_word', full_name='DebugLinkState.recovery_fake_word', index=8, + number=9, 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), + _descriptor.FieldDescriptor( + name='recovery_word_pos', full_name='DebugLinkState.recovery_word_pos', index=9, + number=10, 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='recovery_cipher', full_name='DebugLinkState.recovery_cipher', index=10, + number=11, 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), + _descriptor.FieldDescriptor( + name='recovery_auto_completed_word', full_name='DebugLinkState.recovery_auto_completed_word', index=11, + number=12, 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), + _descriptor.FieldDescriptor( + name='firmware_hash', full_name='DebugLinkState.firmware_hash', 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='storage_hash', full_name='DebugLinkState.storage_hash', 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), + _descriptor.FieldDescriptor( + name='dice_digest', full_name='DebugLinkState.dice_digest', index=14, + number=15, 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=4821, + serialized_end=5185, +) + + +_DEBUGLINKSTOP = _descriptor.Descriptor( + name='DebugLinkStop', + full_name='DebugLinkStop', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5187, + serialized_end=5202, +) + + +_DEBUGLINKLOG = _descriptor.Descriptor( + name='DebugLinkLog', + full_name='DebugLinkLog', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='level', full_name='DebugLinkLog.level', 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='bucket', full_name='DebugLinkLog.bucket', index=1, + number=2, 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), + _descriptor.FieldDescriptor( + name='text', full_name='DebugLinkLog.text', index=2, + number=3, 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=5204, + serialized_end=5263, +) + + +_DEBUGLINKFILLCONFIG = _descriptor.Descriptor( + name='DebugLinkFillConfig', + full_name='DebugLinkFillConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5265, + serialized_end=5286, +) + + +_CHANGEWIPECODE = _descriptor.Descriptor( + name='ChangeWipeCode', + full_name='ChangeWipeCode', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='remove', full_name='ChangeWipeCode.remove', index=0, + number=1, 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=5288, + serialized_end=5320, +) + + +_CLEARSIGNATTESTORGETPUBLICKEY = _descriptor.Descriptor( + name='ClearsignAttestorGetPublicKey', + full_name='ClearsignAttestorGetPublicKey', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5322, + serialized_end=5353, +) + + +_CLEARSIGNATTESTORPUBLICKEY = _descriptor.Descriptor( + name='ClearsignAttestorPublicKey', + full_name='ClearsignAttestorPublicKey', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='public_key', full_name='ClearsignAttestorPublicKey.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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5355, + serialized_end=5403, +) + + +_CLEARSIGNATTESTORSIGN = _descriptor.Descriptor( + name='ClearsignAttestorSign', + full_name='ClearsignAttestorSign', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='payload', full_name='ClearsignAttestorSign.payload', 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=5405, + serialized_end=5445, +) + + +_CLEARSIGNATTESTORSIGNATURE = _descriptor.Descriptor( + name='ClearsignAttestorSignature', + full_name='ClearsignAttestorSignature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='signature', full_name='ClearsignAttestorSignature.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), + _descriptor.FieldDescriptor( + name='public_key', full_name='ClearsignAttestorSignature.public_key', 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=5447, + serialized_end=5514, +) + +_FEATURES.fields_by_name['coins'].message_type = types__pb2._COINTYPE +_FEATURES.fields_by_name['policies'].message_type = types__pb2._POLICYTYPE +_COINTABLE.fields_by_name['table'].message_type = types__pb2._COINTYPE +_FAILURE.fields_by_name['code'].enum_type = types__pb2._FAILURETYPE +_BUTTONREQUEST.fields_by_name['code'].enum_type = types__pb2._BUTTONREQUESTTYPE +_PINMATRIXREQUEST.fields_by_name['type'].enum_type = types__pb2._PINMATRIXREQUESTTYPE +_GETPUBLICKEY.fields_by_name['script_type'].enum_type = types__pb2._INPUTSCRIPTTYPE +_PUBLICKEY.fields_by_name['node'].message_type = types__pb2._HDNODETYPE +_GETADDRESS.fields_by_name['multisig'].message_type = types__pb2._MULTISIGREDEEMSCRIPTTYPE +_GETADDRESS.fields_by_name['script_type'].enum_type = types__pb2._INPUTSCRIPTTYPE +_LOADDEVICE.fields_by_name['node'].message_type = types__pb2._HDNODETYPE +_SIGNMESSAGE.fields_by_name['script_type'].enum_type = types__pb2._INPUTSCRIPTTYPE +_TXREQUEST.fields_by_name['request_type'].enum_type = types__pb2._REQUESTTYPE +_TXREQUEST.fields_by_name['details'].message_type = types__pb2._TXREQUESTDETAILSTYPE +_TXREQUEST.fields_by_name['serialized'].message_type = types__pb2._TXREQUESTSERIALIZEDTYPE +_TXACK.fields_by_name['tx'].message_type = types__pb2._TRANSACTIONTYPE +_RAWTXACK.fields_by_name['tx'].message_type = types__pb2._RAWTRANSACTIONTYPE +_SIGNIDENTITY.fields_by_name['identity'].message_type = types__pb2._IDENTITYTYPE +_APPLYPOLICIES.fields_by_name['policy'].message_type = types__pb2._POLICYTYPE +_DEBUGLINKSTATE.fields_by_name['node'].message_type = types__pb2._HDNODETYPE +DESCRIPTOR.message_types_by_name['Initialize'] = _INITIALIZE +DESCRIPTOR.message_types_by_name['GetFeatures'] = _GETFEATURES +DESCRIPTOR.message_types_by_name['Features'] = _FEATURES +DESCRIPTOR.message_types_by_name['GetCoinTable'] = _GETCOINTABLE +DESCRIPTOR.message_types_by_name['CoinTable'] = _COINTABLE +DESCRIPTOR.message_types_by_name['ClearSession'] = _CLEARSESSION +DESCRIPTOR.message_types_by_name['ApplySettings'] = _APPLYSETTINGS +DESCRIPTOR.message_types_by_name['ChangePin'] = _CHANGEPIN +DESCRIPTOR.message_types_by_name['Ping'] = _PING +DESCRIPTOR.message_types_by_name['Success'] = _SUCCESS +DESCRIPTOR.message_types_by_name['Failure'] = _FAILURE +DESCRIPTOR.message_types_by_name['ButtonRequest'] = _BUTTONREQUEST +DESCRIPTOR.message_types_by_name['ButtonAck'] = _BUTTONACK +DESCRIPTOR.message_types_by_name['PinMatrixRequest'] = _PINMATRIXREQUEST +DESCRIPTOR.message_types_by_name['PinMatrixAck'] = _PINMATRIXACK +DESCRIPTOR.message_types_by_name['Cancel'] = _CANCEL +DESCRIPTOR.message_types_by_name['PassphraseRequest'] = _PASSPHRASEREQUEST +DESCRIPTOR.message_types_by_name['PassphraseAck'] = _PASSPHRASEACK +DESCRIPTOR.message_types_by_name['GetEntropy'] = _GETENTROPY +DESCRIPTOR.message_types_by_name['Entropy'] = _ENTROPY +DESCRIPTOR.message_types_by_name['GetPublicKey'] = _GETPUBLICKEY +DESCRIPTOR.message_types_by_name['PublicKey'] = _PUBLICKEY +DESCRIPTOR.message_types_by_name['GetAddress'] = _GETADDRESS +DESCRIPTOR.message_types_by_name['Address'] = _ADDRESS +DESCRIPTOR.message_types_by_name['WipeDevice'] = _WIPEDEVICE +DESCRIPTOR.message_types_by_name['LoadDevice'] = _LOADDEVICE +DESCRIPTOR.message_types_by_name['ResetDevice'] = _RESETDEVICE +DESCRIPTOR.message_types_by_name['EntropyRequest'] = _ENTROPYREQUEST +DESCRIPTOR.message_types_by_name['EntropyAck'] = _ENTROPYACK +DESCRIPTOR.message_types_by_name['RecoveryDevice'] = _RECOVERYDEVICE +DESCRIPTOR.message_types_by_name['WordRequest'] = _WORDREQUEST +DESCRIPTOR.message_types_by_name['WordAck'] = _WORDACK +DESCRIPTOR.message_types_by_name['CharacterRequest'] = _CHARACTERREQUEST +DESCRIPTOR.message_types_by_name['CharacterAck'] = _CHARACTERACK +DESCRIPTOR.message_types_by_name['SignMessage'] = _SIGNMESSAGE +DESCRIPTOR.message_types_by_name['VerifyMessage'] = _VERIFYMESSAGE +DESCRIPTOR.message_types_by_name['MessageSignature'] = _MESSAGESIGNATURE +DESCRIPTOR.message_types_by_name['EncryptMessage'] = _ENCRYPTMESSAGE +DESCRIPTOR.message_types_by_name['EncryptedMessage'] = _ENCRYPTEDMESSAGE +DESCRIPTOR.message_types_by_name['DecryptMessage'] = _DECRYPTMESSAGE +DESCRIPTOR.message_types_by_name['DecryptedMessage'] = _DECRYPTEDMESSAGE +DESCRIPTOR.message_types_by_name['CipherKeyValue'] = _CIPHERKEYVALUE +DESCRIPTOR.message_types_by_name['CipheredKeyValue'] = _CIPHEREDKEYVALUE +DESCRIPTOR.message_types_by_name['GetBip85Mnemonic'] = _GETBIP85MNEMONIC +DESCRIPTOR.message_types_by_name['Bip85Mnemonic'] = _BIP85MNEMONIC +DESCRIPTOR.message_types_by_name['SignTx'] = _SIGNTX +DESCRIPTOR.message_types_by_name['TxRequest'] = _TXREQUEST +DESCRIPTOR.message_types_by_name['TxAck'] = _TXACK +DESCRIPTOR.message_types_by_name['RawTxAck'] = _RAWTXACK +DESCRIPTOR.message_types_by_name['SignIdentity'] = _SIGNIDENTITY +DESCRIPTOR.message_types_by_name['SignedIdentity'] = _SIGNEDIDENTITY +DESCRIPTOR.message_types_by_name['ApplyPolicies'] = _APPLYPOLICIES +DESCRIPTOR.message_types_by_name['FlashHash'] = _FLASHHASH +DESCRIPTOR.message_types_by_name['FlashWrite'] = _FLASHWRITE +DESCRIPTOR.message_types_by_name['FlashHashResponse'] = _FLASHHASHRESPONSE +DESCRIPTOR.message_types_by_name['DebugLinkFlashDump'] = _DEBUGLINKFLASHDUMP +DESCRIPTOR.message_types_by_name['DebugLinkFlashDumpResponse'] = _DEBUGLINKFLASHDUMPRESPONSE +DESCRIPTOR.message_types_by_name['SoftReset'] = _SOFTRESET +DESCRIPTOR.message_types_by_name['FirmwareErase'] = _FIRMWAREERASE +DESCRIPTOR.message_types_by_name['FirmwareUpload'] = _FIRMWAREUPLOAD +DESCRIPTOR.message_types_by_name['DebugLinkDecision'] = _DEBUGLINKDECISION +DESCRIPTOR.message_types_by_name['DebugLinkGetState'] = _DEBUGLINKGETSTATE +DESCRIPTOR.message_types_by_name['DebugLinkState'] = _DEBUGLINKSTATE +DESCRIPTOR.message_types_by_name['DebugLinkStop'] = _DEBUGLINKSTOP +DESCRIPTOR.message_types_by_name['DebugLinkLog'] = _DEBUGLINKLOG +DESCRIPTOR.message_types_by_name['DebugLinkFillConfig'] = _DEBUGLINKFILLCONFIG +DESCRIPTOR.message_types_by_name['ChangeWipeCode'] = _CHANGEWIPECODE +DESCRIPTOR.message_types_by_name['ClearsignAttestorGetPublicKey'] = _CLEARSIGNATTESTORGETPUBLICKEY +DESCRIPTOR.message_types_by_name['ClearsignAttestorPublicKey'] = _CLEARSIGNATTESTORPUBLICKEY +DESCRIPTOR.message_types_by_name['ClearsignAttestorSign'] = _CLEARSIGNATTESTORSIGN +DESCRIPTOR.message_types_by_name['ClearsignAttestorSignature'] = _CLEARSIGNATTESTORSIGNATURE +DESCRIPTOR.enum_types_by_name['MessageType'] = _MESSAGETYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Initialize = _reflection.GeneratedProtocolMessageType('Initialize', (_message.Message,), dict( + DESCRIPTOR = _INITIALIZE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Initialize) + )) +_sym_db.RegisterMessage(Initialize) + +GetFeatures = _reflection.GeneratedProtocolMessageType('GetFeatures', (_message.Message,), dict( + DESCRIPTOR = _GETFEATURES, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetFeatures) + )) +_sym_db.RegisterMessage(GetFeatures) + +Features = _reflection.GeneratedProtocolMessageType('Features', (_message.Message,), dict( + DESCRIPTOR = _FEATURES, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Features) + )) +_sym_db.RegisterMessage(Features) + +GetCoinTable = _reflection.GeneratedProtocolMessageType('GetCoinTable', (_message.Message,), dict( + DESCRIPTOR = _GETCOINTABLE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetCoinTable) + )) +_sym_db.RegisterMessage(GetCoinTable) + +CoinTable = _reflection.GeneratedProtocolMessageType('CoinTable', (_message.Message,), dict( + DESCRIPTOR = _COINTABLE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:CoinTable) + )) +_sym_db.RegisterMessage(CoinTable) + +ClearSession = _reflection.GeneratedProtocolMessageType('ClearSession', (_message.Message,), dict( + DESCRIPTOR = _CLEARSESSION, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ClearSession) + )) +_sym_db.RegisterMessage(ClearSession) + +ApplySettings = _reflection.GeneratedProtocolMessageType('ApplySettings', (_message.Message,), dict( + DESCRIPTOR = _APPLYSETTINGS, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ApplySettings) + )) +_sym_db.RegisterMessage(ApplySettings) + +ChangePin = _reflection.GeneratedProtocolMessageType('ChangePin', (_message.Message,), dict( + DESCRIPTOR = _CHANGEPIN, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ChangePin) + )) +_sym_db.RegisterMessage(ChangePin) + +Ping = _reflection.GeneratedProtocolMessageType('Ping', (_message.Message,), dict( + DESCRIPTOR = _PING, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Ping) + )) +_sym_db.RegisterMessage(Ping) + +Success = _reflection.GeneratedProtocolMessageType('Success', (_message.Message,), dict( + DESCRIPTOR = _SUCCESS, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Success) + )) +_sym_db.RegisterMessage(Success) + +Failure = _reflection.GeneratedProtocolMessageType('Failure', (_message.Message,), dict( + DESCRIPTOR = _FAILURE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Failure) + )) +_sym_db.RegisterMessage(Failure) + +ButtonRequest = _reflection.GeneratedProtocolMessageType('ButtonRequest', (_message.Message,), dict( + DESCRIPTOR = _BUTTONREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ButtonRequest) + )) +_sym_db.RegisterMessage(ButtonRequest) + +ButtonAck = _reflection.GeneratedProtocolMessageType('ButtonAck', (_message.Message,), dict( + DESCRIPTOR = _BUTTONACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ButtonAck) + )) +_sym_db.RegisterMessage(ButtonAck) + +PinMatrixRequest = _reflection.GeneratedProtocolMessageType('PinMatrixRequest', (_message.Message,), dict( + DESCRIPTOR = _PINMATRIXREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:PinMatrixRequest) + )) +_sym_db.RegisterMessage(PinMatrixRequest) + +PinMatrixAck = _reflection.GeneratedProtocolMessageType('PinMatrixAck', (_message.Message,), dict( + DESCRIPTOR = _PINMATRIXACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:PinMatrixAck) + )) +_sym_db.RegisterMessage(PinMatrixAck) + +Cancel = _reflection.GeneratedProtocolMessageType('Cancel', (_message.Message,), dict( + DESCRIPTOR = _CANCEL, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Cancel) + )) +_sym_db.RegisterMessage(Cancel) + +PassphraseRequest = _reflection.GeneratedProtocolMessageType('PassphraseRequest', (_message.Message,), dict( + DESCRIPTOR = _PASSPHRASEREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:PassphraseRequest) + )) +_sym_db.RegisterMessage(PassphraseRequest) + +PassphraseAck = _reflection.GeneratedProtocolMessageType('PassphraseAck', (_message.Message,), dict( + DESCRIPTOR = _PASSPHRASEACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:PassphraseAck) + )) +_sym_db.RegisterMessage(PassphraseAck) + +GetEntropy = _reflection.GeneratedProtocolMessageType('GetEntropy', (_message.Message,), dict( + DESCRIPTOR = _GETENTROPY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetEntropy) + )) +_sym_db.RegisterMessage(GetEntropy) + +Entropy = _reflection.GeneratedProtocolMessageType('Entropy', (_message.Message,), dict( + DESCRIPTOR = _ENTROPY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Entropy) + )) +_sym_db.RegisterMessage(Entropy) + +GetPublicKey = _reflection.GeneratedProtocolMessageType('GetPublicKey', (_message.Message,), dict( + DESCRIPTOR = _GETPUBLICKEY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetPublicKey) + )) +_sym_db.RegisterMessage(GetPublicKey) + +PublicKey = _reflection.GeneratedProtocolMessageType('PublicKey', (_message.Message,), dict( + DESCRIPTOR = _PUBLICKEY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:PublicKey) + )) +_sym_db.RegisterMessage(PublicKey) + +GetAddress = _reflection.GeneratedProtocolMessageType('GetAddress', (_message.Message,), dict( + DESCRIPTOR = _GETADDRESS, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetAddress) + )) +_sym_db.RegisterMessage(GetAddress) + +Address = _reflection.GeneratedProtocolMessageType('Address', (_message.Message,), dict( + DESCRIPTOR = _ADDRESS, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Address) + )) +_sym_db.RegisterMessage(Address) + +WipeDevice = _reflection.GeneratedProtocolMessageType('WipeDevice', (_message.Message,), dict( + DESCRIPTOR = _WIPEDEVICE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:WipeDevice) + )) +_sym_db.RegisterMessage(WipeDevice) + +LoadDevice = _reflection.GeneratedProtocolMessageType('LoadDevice', (_message.Message,), dict( + DESCRIPTOR = _LOADDEVICE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:LoadDevice) + )) +_sym_db.RegisterMessage(LoadDevice) + +ResetDevice = _reflection.GeneratedProtocolMessageType('ResetDevice', (_message.Message,), dict( + DESCRIPTOR = _RESETDEVICE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ResetDevice) + )) +_sym_db.RegisterMessage(ResetDevice) + +EntropyRequest = _reflection.GeneratedProtocolMessageType('EntropyRequest', (_message.Message,), dict( + DESCRIPTOR = _ENTROPYREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:EntropyRequest) + )) +_sym_db.RegisterMessage(EntropyRequest) + +EntropyAck = _reflection.GeneratedProtocolMessageType('EntropyAck', (_message.Message,), dict( + DESCRIPTOR = _ENTROPYACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:EntropyAck) + )) +_sym_db.RegisterMessage(EntropyAck) + +RecoveryDevice = _reflection.GeneratedProtocolMessageType('RecoveryDevice', (_message.Message,), dict( + DESCRIPTOR = _RECOVERYDEVICE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:RecoveryDevice) + )) +_sym_db.RegisterMessage(RecoveryDevice) + +WordRequest = _reflection.GeneratedProtocolMessageType('WordRequest', (_message.Message,), dict( + DESCRIPTOR = _WORDREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:WordRequest) + )) +_sym_db.RegisterMessage(WordRequest) + +WordAck = _reflection.GeneratedProtocolMessageType('WordAck', (_message.Message,), dict( + DESCRIPTOR = _WORDACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:WordAck) + )) +_sym_db.RegisterMessage(WordAck) + +CharacterRequest = _reflection.GeneratedProtocolMessageType('CharacterRequest', (_message.Message,), dict( + DESCRIPTOR = _CHARACTERREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:CharacterRequest) + )) +_sym_db.RegisterMessage(CharacterRequest) + +CharacterAck = _reflection.GeneratedProtocolMessageType('CharacterAck', (_message.Message,), dict( + DESCRIPTOR = _CHARACTERACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:CharacterAck) + )) +_sym_db.RegisterMessage(CharacterAck) + +SignMessage = _reflection.GeneratedProtocolMessageType('SignMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:SignMessage) + )) +_sym_db.RegisterMessage(SignMessage) + +VerifyMessage = _reflection.GeneratedProtocolMessageType('VerifyMessage', (_message.Message,), dict( + DESCRIPTOR = _VERIFYMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:VerifyMessage) + )) +_sym_db.RegisterMessage(VerifyMessage) + +MessageSignature = _reflection.GeneratedProtocolMessageType('MessageSignature', (_message.Message,), dict( + DESCRIPTOR = _MESSAGESIGNATURE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:MessageSignature) + )) +_sym_db.RegisterMessage(MessageSignature) + +EncryptMessage = _reflection.GeneratedProtocolMessageType('EncryptMessage', (_message.Message,), dict( + DESCRIPTOR = _ENCRYPTMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:EncryptMessage) + )) +_sym_db.RegisterMessage(EncryptMessage) + +EncryptedMessage = _reflection.GeneratedProtocolMessageType('EncryptedMessage', (_message.Message,), dict( + DESCRIPTOR = _ENCRYPTEDMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:EncryptedMessage) + )) +_sym_db.RegisterMessage(EncryptedMessage) + +DecryptMessage = _reflection.GeneratedProtocolMessageType('DecryptMessage', (_message.Message,), dict( + DESCRIPTOR = _DECRYPTMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DecryptMessage) + )) +_sym_db.RegisterMessage(DecryptMessage) + +DecryptedMessage = _reflection.GeneratedProtocolMessageType('DecryptedMessage', (_message.Message,), dict( + DESCRIPTOR = _DECRYPTEDMESSAGE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DecryptedMessage) + )) +_sym_db.RegisterMessage(DecryptedMessage) + +CipherKeyValue = _reflection.GeneratedProtocolMessageType('CipherKeyValue', (_message.Message,), dict( + DESCRIPTOR = _CIPHERKEYVALUE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:CipherKeyValue) + )) +_sym_db.RegisterMessage(CipherKeyValue) + +CipheredKeyValue = _reflection.GeneratedProtocolMessageType('CipheredKeyValue', (_message.Message,), dict( + DESCRIPTOR = _CIPHEREDKEYVALUE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:CipheredKeyValue) + )) +_sym_db.RegisterMessage(CipheredKeyValue) + +GetBip85Mnemonic = _reflection.GeneratedProtocolMessageType('GetBip85Mnemonic', (_message.Message,), dict( + DESCRIPTOR = _GETBIP85MNEMONIC, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:GetBip85Mnemonic) + )) +_sym_db.RegisterMessage(GetBip85Mnemonic) + +Bip85Mnemonic = _reflection.GeneratedProtocolMessageType('Bip85Mnemonic', (_message.Message,), dict( + DESCRIPTOR = _BIP85MNEMONIC, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:Bip85Mnemonic) + )) +_sym_db.RegisterMessage(Bip85Mnemonic) + +SignTx = _reflection.GeneratedProtocolMessageType('SignTx', (_message.Message,), dict( + DESCRIPTOR = _SIGNTX, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:SignTx) + )) +_sym_db.RegisterMessage(SignTx) + +TxRequest = _reflection.GeneratedProtocolMessageType('TxRequest', (_message.Message,), dict( + DESCRIPTOR = _TXREQUEST, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:TxRequest) + )) +_sym_db.RegisterMessage(TxRequest) + +TxAck = _reflection.GeneratedProtocolMessageType('TxAck', (_message.Message,), dict( + DESCRIPTOR = _TXACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:TxAck) + )) +_sym_db.RegisterMessage(TxAck) + +RawTxAck = _reflection.GeneratedProtocolMessageType('RawTxAck', (_message.Message,), dict( + DESCRIPTOR = _RAWTXACK, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:RawTxAck) + )) +_sym_db.RegisterMessage(RawTxAck) + +SignIdentity = _reflection.GeneratedProtocolMessageType('SignIdentity', (_message.Message,), dict( + DESCRIPTOR = _SIGNIDENTITY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:SignIdentity) + )) +_sym_db.RegisterMessage(SignIdentity) + +SignedIdentity = _reflection.GeneratedProtocolMessageType('SignedIdentity', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDIDENTITY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:SignedIdentity) + )) +_sym_db.RegisterMessage(SignedIdentity) + +ApplyPolicies = _reflection.GeneratedProtocolMessageType('ApplyPolicies', (_message.Message,), dict( + DESCRIPTOR = _APPLYPOLICIES, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ApplyPolicies) + )) +_sym_db.RegisterMessage(ApplyPolicies) + +FlashHash = _reflection.GeneratedProtocolMessageType('FlashHash', (_message.Message,), dict( + DESCRIPTOR = _FLASHHASH, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:FlashHash) + )) +_sym_db.RegisterMessage(FlashHash) + +FlashWrite = _reflection.GeneratedProtocolMessageType('FlashWrite', (_message.Message,), dict( + DESCRIPTOR = _FLASHWRITE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:FlashWrite) + )) +_sym_db.RegisterMessage(FlashWrite) + +FlashHashResponse = _reflection.GeneratedProtocolMessageType('FlashHashResponse', (_message.Message,), dict( + DESCRIPTOR = _FLASHHASHRESPONSE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:FlashHashResponse) + )) +_sym_db.RegisterMessage(FlashHashResponse) + +DebugLinkFlashDump = _reflection.GeneratedProtocolMessageType('DebugLinkFlashDump', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKFLASHDUMP, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkFlashDump) + )) +_sym_db.RegisterMessage(DebugLinkFlashDump) + +DebugLinkFlashDumpResponse = _reflection.GeneratedProtocolMessageType('DebugLinkFlashDumpResponse', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKFLASHDUMPRESPONSE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkFlashDumpResponse) + )) +_sym_db.RegisterMessage(DebugLinkFlashDumpResponse) + +SoftReset = _reflection.GeneratedProtocolMessageType('SoftReset', (_message.Message,), dict( + DESCRIPTOR = _SOFTRESET, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:SoftReset) + )) +_sym_db.RegisterMessage(SoftReset) + +FirmwareErase = _reflection.GeneratedProtocolMessageType('FirmwareErase', (_message.Message,), dict( + DESCRIPTOR = _FIRMWAREERASE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:FirmwareErase) + )) +_sym_db.RegisterMessage(FirmwareErase) + +FirmwareUpload = _reflection.GeneratedProtocolMessageType('FirmwareUpload', (_message.Message,), dict( + DESCRIPTOR = _FIRMWAREUPLOAD, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:FirmwareUpload) + )) +_sym_db.RegisterMessage(FirmwareUpload) + +DebugLinkDecision = _reflection.GeneratedProtocolMessageType('DebugLinkDecision', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKDECISION, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkDecision) + )) +_sym_db.RegisterMessage(DebugLinkDecision) + +DebugLinkGetState = _reflection.GeneratedProtocolMessageType('DebugLinkGetState', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKGETSTATE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkGetState) + )) +_sym_db.RegisterMessage(DebugLinkGetState) + +DebugLinkState = _reflection.GeneratedProtocolMessageType('DebugLinkState', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKSTATE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkState) + )) +_sym_db.RegisterMessage(DebugLinkState) + +DebugLinkStop = _reflection.GeneratedProtocolMessageType('DebugLinkStop', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKSTOP, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkStop) + )) +_sym_db.RegisterMessage(DebugLinkStop) + +DebugLinkLog = _reflection.GeneratedProtocolMessageType('DebugLinkLog', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKLOG, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkLog) + )) +_sym_db.RegisterMessage(DebugLinkLog) + +DebugLinkFillConfig = _reflection.GeneratedProtocolMessageType('DebugLinkFillConfig', (_message.Message,), dict( + DESCRIPTOR = _DEBUGLINKFILLCONFIG, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:DebugLinkFillConfig) + )) +_sym_db.RegisterMessage(DebugLinkFillConfig) + +ChangeWipeCode = _reflection.GeneratedProtocolMessageType('ChangeWipeCode', (_message.Message,), dict( + DESCRIPTOR = _CHANGEWIPECODE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ChangeWipeCode) + )) +_sym_db.RegisterMessage(ChangeWipeCode) + +ClearsignAttestorGetPublicKey = _reflection.GeneratedProtocolMessageType('ClearsignAttestorGetPublicKey', (_message.Message,), dict( + DESCRIPTOR = _CLEARSIGNATTESTORGETPUBLICKEY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ClearsignAttestorGetPublicKey) + )) +_sym_db.RegisterMessage(ClearsignAttestorGetPublicKey) + +ClearsignAttestorPublicKey = _reflection.GeneratedProtocolMessageType('ClearsignAttestorPublicKey', (_message.Message,), dict( + DESCRIPTOR = _CLEARSIGNATTESTORPUBLICKEY, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ClearsignAttestorPublicKey) + )) +_sym_db.RegisterMessage(ClearsignAttestorPublicKey) + +ClearsignAttestorSign = _reflection.GeneratedProtocolMessageType('ClearsignAttestorSign', (_message.Message,), dict( + DESCRIPTOR = _CLEARSIGNATTESTORSIGN, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ClearsignAttestorSign) + )) +_sym_db.RegisterMessage(ClearsignAttestorSign) + +ClearsignAttestorSignature = _reflection.GeneratedProtocolMessageType('ClearsignAttestorSignature', (_message.Message,), dict( + DESCRIPTOR = _CLEARSIGNATTESTORSIGNATURE, + __module__ = 'messages_pb2' + # @@protoc_insertion_point(class_scope:ClearsignAttestorSignature) + )) +_sym_db.RegisterMessage(ClearsignAttestorSignature) + + +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\032com.keepkey.deviceprotocolB\016KeepKeyMessage')) +_MESSAGETYPE.values_by_name["MessageType_Initialize"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Initialize"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Ping"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Ping"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Success"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Success"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Failure"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Failure"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ChangePin"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ChangePin"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_WipeDevice"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_WipeDevice"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_FirmwareErase"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_FirmwareErase"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_FirmwareUpload"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_FirmwareUpload"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetEntropy"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetEntropy"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Entropy"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Entropy"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_PublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_PublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_LoadDevice"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_LoadDevice"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ResetDevice"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ResetDevice"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Features"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Features"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_PinMatrixRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_PinMatrixRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_PinMatrixAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_PinMatrixAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Cancel"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Cancel"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TxRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TxRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TxAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TxAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CipherKeyValue"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CipherKeyValue"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ClearSession"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ClearSession"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ApplySettings"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ApplySettings"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ButtonRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ButtonRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ButtonAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ButtonAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Address"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Address"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EntropyRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EntropyRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EntropyAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EntropyAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_VerifyMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_VerifyMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_MessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_PassphraseRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_PassphraseRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_PassphraseAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_PassphraseAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RecoveryDevice"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RecoveryDevice"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_WordRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_WordRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_WordAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_WordAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CipheredKeyValue"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CipheredKeyValue"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EncryptMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EncryptMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EncryptedMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EncryptedMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DecryptMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DecryptMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DecryptedMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DecryptedMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SignIdentity"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SignIdentity"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SignedIdentity"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SignedIdentity"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetFeatures"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetFeatures"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTxRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTxRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTxAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTxAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CharacterRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CharacterRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CharacterAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CharacterAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RawTxAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RawTxAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ApplyPolicies"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ApplyPolicies"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_FlashHash"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_FlashHash"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_FlashWrite"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_FlashWrite"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_FlashHashResponse"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_FlashHashResponse"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDump"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDump"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDumpResponse"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFlashDumpResponse"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SoftReset"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SoftReset"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkDecision"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkDecision"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkGetState"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkGetState"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkState"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkState"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkStop"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkStop"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\240\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkLog"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkLog"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFillConfig"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_DebugLinkFillConfig"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\250\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetCoinTable"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetCoinTable"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CoinTable"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CoinTable"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumVerifyMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumVerifyMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ChangeWipeCode"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ChangeWipeCode"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedHash"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedHash"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Ethereum712TypesValues"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Ethereum712TypesValues"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTxMetadata"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTxMetadata"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumMetadataAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumMetadataAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_LoadClearsignSigner"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_LoadClearsignSigner"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedData"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumSignTypedData"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataStructAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumTypedDataValueAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinition"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinition"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionChunk"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EthereumClearSignDefinitionChunk"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_GetBip85Mnemonic"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_GetBip85Mnemonic"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_Bip85Mnemonic"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_Bip85Mnemonic"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RippleGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RippleGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RippleAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RippleAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RippleSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RippleSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_RippleSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_RippleSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainMsgRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainMsgRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainMsgAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainMsgAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ThorchainSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ThorchainSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosGetPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosGetPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosTxActionRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosTxActionRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosTxActionAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosTxActionAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_EosSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_EosSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NanoGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NanoGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NanoAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NanoAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NanoSignTx"].has_options = True +_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_SolanaSignOffchainMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaSignOffchainMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_SolanaOffchainMessageSignature"]._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 +_MESSAGETYPE.values_by_name["MessageType_BinanceAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceGetPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceGetPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinancePublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinancePublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceTxRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceTxRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceTransferMsg"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceTransferMsg"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceOrderMsg"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceOrderMsg"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceCancelMsg"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceCancelMsg"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_BinanceSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_BinanceSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgDelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgDelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgUndelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgUndelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRedelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRedelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRewards"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgRewards"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgIBCTransfer"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_CosmosMsgIBCTransfer"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgSend"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgSend"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgDelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgDelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgUndelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgUndelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRedelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRedelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRewards"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgRewards"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgIBCTransfer"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TendermintMsgIBCTransfer"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSend"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSend"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgDelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgDelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgUndelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgUndelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRedelegate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRedelegate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRewards"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgRewards"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPAdd"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPAdd"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPRemove"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPRemove"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPStake"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPStake"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPUnstake"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgLPUnstake"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgIBCTransfer"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgIBCTransfer"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSwap"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisMsgSwap"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_OsmosisSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_OsmosisSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MayachainGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_MayachainGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MayachainAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_MayachainAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MayachainSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_MayachainSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MayachainMsgRequest"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_MayachainMsgRequest"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_MayachainMsgAck"].has_options = True +_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')) +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentInput"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentInput"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentSigned"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentSigned"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashDisplayAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashDisplayAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentOutput"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentOutput"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentAck"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ZcashTransparentAck"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronVerifyMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronSignTypedHash"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TronTypedDataSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_TonMessageSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HivePublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HivePublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKeys"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveGetPublicKeys"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HivePublicKeys"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HivePublicKeys"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignAccountCreate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignAccountCreate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountCreate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountCreate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignAccountUpdate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignAccountUpdate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountUpdate"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignedAccountUpdate"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NearGetAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NearGetAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NearAddress"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NearAddress"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NearSignTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NearSignTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_NearSignedTx"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_NearSignedTx"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignedMessage"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignedMessage"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignOperations"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignOperations"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_HiveSignedOperations"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_HiveSignedOperations"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorGetPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorGetPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorPublicKey"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorPublicKey"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSign"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSign"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\220\265\030\001')) +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSignature"].has_options = True +_MESSAGETYPE.values_by_name["MessageType_ClearsignAttestorSignature"]._options = _descriptor._ParseOptions(descriptor_pb2.EnumValueOptions(), _b('\230\265\030\001')) # @@protoc_insertion_point(module_scope) diff --git a/keepkeylib/tx_api.py b/keepkeylib/tx_api.py index 9a17324a..af2d45c1 100644 --- a/keepkeylib/tx_api.py +++ b/keepkeylib/tx_api.py @@ -21,11 +21,24 @@ from decimal import Decimal import requests import json +import os import struct from . import types_pb2 as proto_types cache_dir = None +offline_only = False + + +class OfflineFixtureError(Exception): + """An authoritative transaction fixture is missing or malformed.""" + + +def configure_offline_fixtures(path): + """Make transaction lookup fail closed against a fixed fixture tree.""" + global cache_dir, offline_only + cache_dir = os.path.abspath(path) + offline_only = True def pack_varint(n): @@ -46,15 +59,38 @@ def __init__(self, network, url): self.url = url def fetch_json(self, url, resource, resourceid): - global cache_dir + global cache_dir, offline_only + cache_file = None if cache_dir: - cache_file = '%s/%s_%s_%s.json' % (cache_dir, self.network, resource, resourceid) - try: # looking into cache first + fixture_name = '%s_%s_%s.json' % ( + self.network, resource, resourceid) + if os.path.basename(fixture_name) != fixture_name: + raise OfflineFixtureError( + 'Invalid fixture key: network=%s resource=%s id=%s' % + (self.network, resource, resourceid)) + cache_file = os.path.join(cache_dir, fixture_name) + try: # looking into cache first with open(cache_file) as f: - j = json.load(f) - return j - except: - pass + return json.load(f) + except OSError as exc: + if offline_only: + raise OfflineFixtureError( + 'Missing offline transaction fixture: ' + 'network=%s resource=%s id=%s path=%s' % + (self.network, resource, resourceid, cache_file) + ) from exc + except (TypeError, ValueError) as exc: + if offline_only: + raise OfflineFixtureError( + 'Invalid offline transaction fixture: ' + 'network=%s resource=%s id=%s path=%s' % + (self.network, resource, resourceid, cache_file) + ) from exc + if offline_only: + raise OfflineFixtureError( + 'Offline transaction fixtures are enabled without a fixture ' + 'directory: network=%s resource=%s id=%s' % + (self.network, resource, resourceid)) try: # print('request %s/%s/%s' % (self.url, resource, resourceid)) r = requests.get('%s/%s/%s' % (self.url, resource, resourceid), headers={'User-agent': 'Mozilla/5.0'}) diff --git a/scripts/generate-test-report.py b/scripts/generate-test-report.py index 07580598..8cb47d5d 100644 --- a/scripts/generate-test-report.py +++ b/scripts/generate-test-report.py @@ -216,6 +216,22 @@ def ver_t(s): parts = (s.split('.') + ['0', '0', '0'])[:3] return tuple(int(''.join(ch for ch in p if ch.isdigit()) or '0') for p in parts) def ver_ge(a, b): return ver_t(a) >= ver_t(b) + +# Tests whose newer fail-closed behavior deliberately returns before drawing a +# confirmation screen. Keep their historical catalog text, but do not schedule +# or audit an OLED capture once the refusal behavior is active. +_NO_SCREEN_FROM = { + ('test_msg_signtx_ethereum_erc20', 'test_approve_all'): '7.14.2', +} + + +def _screens_for(fw_version, mod, meth, screens): + floor = _NO_SCREEN_FROM.get((mod, meth)) + if floor and ver_ge(fw_version, floor): + return [] + return screens + + def _w(text, n=95): words, lines, cur = text.split(), [], '' for w in words: @@ -343,7 +359,7 @@ def detect_fw(): # Census of everything the merged JUnit actually contained, so the report can # state how much of the run it covers. Without this the PDF silently implies # that its catalog IS the test suite -- an RC audit read "no dice in the report" -# as "dice is untested" when test_reset_device_dice had in fact run green. +# as "dice is untested" when the dice reset test had in fact run green. JUNIT_CENSUS = {'ran': 0, 'skipped': 0, 'native': 0} @@ -431,6 +447,9 @@ def parse_junit(path): ('test_msg_thorchain_signtx', 'test_thorchain_sign_tx'), ('test_msg_mayachain_signtx', 'test_mayachain_sign_tx_memos'), ('test_msg_osmosis_signtx', 'test_osmosis_swap_max_fields_are_fully_paged'), + # Every screen of a certified Solana review is a claim about what the user + # was shown before signing. + ('test_msg_solana_schema_v2', 'test_certified_soltoshi_join_reviews_every_screen'), } def _v_catalog_tests(start_id=17): @@ -792,7 +811,7 @@ def _arg_shown(a): ['Wordlist rejection warning']), ]), - ('K', 'Seed Generation Hardening (7.15)', '7.15.0', + ('K', 'Seed Generation Hardening (7.14.3+)', '7.14.3', 'The 7.15 changes to how a seed comes into existence: user-supplied dice entropy folded in ' 'on-device, and the PIN key-derivation rewrap. These ran green from the first 7.15 RC but ' 'appeared nowhere in this report, because the catalog could not reference native firmware ' @@ -809,14 +828,45 @@ def _arg_shown(a): 'PIN KDF: a v16 storage blob must still unlock and then rewrap to v19, or the upgrade bricks.', ], [ - ('K1', 'test_msg_resetdevice', 'test_reset_device_dice', - 'Dice entropy end-to-end', - 'Drives the full on-device dice flow over DebugLink: 99 rolls injected in chunks with undo ' - 'exercised, extras past the cap dropped. Asserts the device-computed digest equals ' - 'SHA256 of exactly the expected roll string, then derives the mnemonic from the post-mix ' - 'internal entropy and compares -- which is what proves the rolls actually reached the seed ' - 'rather than being collected and discarded.', - ['Dice entry screen', 'Digest confirmation']), + ('K1', 'test_msg_resetdevice', 'test_reset_device_dice_mixed_is_verifiable', + 'Dice + device entropy, verified offline', + 'Host selects MIXED (dice_entropy alone). The device shows the consent screen naming the ' + 'mode, then its own 32-byte draw as 24 BIP-39 words BEFORE any roll, then collects 99 rolls ' + 'over DebugLink with undo exercised. The test decodes the 24 words with its own ' + 'checksum-verified BIP-39 decoder, recomputes ' + 'seed = SHA256d(tag || draw || SHA256(tag || rolls)) from the published formula -- with the ' + 'host\'s EntropyAck bytes nowhere in it -- and requires the backup words to match. That is ' + 'the proof a user can repeat with tools/verify_dice_seed.py: the rolls reached the seed, ' + 'the device draw was the one it committed to, and the host contributed nothing.', + ['Mode consent', 'Dice entry screen', 'Digest confirmation']), + ('K1b', 'test_msg_resetdevice', 'test_reset_device_dice_only_is_verifiable', + 'Dice only, verified offline', + 'Host selects DICE ONLY (dice_entropy + dice_only), 50 rolls for a 12-word seed. No device ' + 'words are shown -- the rolls are the entire derivation -- and the test requires the backup ' + 'words to equal BIP39(SHA256(rolls)) while sending a nonzero EntropyAck that must be ' + 'ignored. Byte-identical to Coldcard\'s Dice-Rolls-Only.', + ['Mode consent', 'Dice entry screen', 'Digest confirmation']), + ('K1c', 'test_msg_resetdevice', 'test_reset_device_dice_rejects_biased_rolls', + 'Loaded die is refused', + 'Fifty ones -- one face on 100% of the rolls. Refused with SyntaxError before any digest ' + 'is drawn, per Coldcard\'s 30%-per-face rule, so a biased die never becomes a wallet.', + []), + ('K1d', 'test_msg_resetdevice', 'test_reset_device_dice_only_requires_dice_entropy', + 'dice_only without dice_entropy is refused', + 'The rolls-only derivation is a modifier of the dice ceremony, not a ceremony of its own; ' + 'the request is refused before any screen.', + []), + ('K1e', 'test_msg_resetdevice', 'test_reset_device_dice_refuses_no_backup', + 'Dice with no_backup is refused', + 'The dice modes exist to be checked against the backup words. A reset that never shows ' + 'them has nothing to verify and would put seed material on the screen under a WARNING ' + 'that recovery is impossible; refused before any screen.', + []), + ('K1f', 'test_msg_resetdevice', 'test_reset_device_dice_consent_cancel_aborts', + 'Cancel at the consent screen aborts everything', + 'The consent screen\'s only "no" is the host\'s Cancel. Asserts ActionCancelled, that a ' + 'subsequent EntropyAck finds no armed ceremony, and that the device is still uninitialized.', + []), ('K2', 'test_msg_resetdevice', 'test_reset_reentry_disarms_entropy_ack', 'Aborted reset disarms EntropyAck', 'Regression for a host-chosen-seed hole: reset_init aborts left awaiting_entropy set from ' @@ -829,25 +879,48 @@ def _arg_shown(a): 'd6 carries log2(6)=2.585 bits, so 128/192/256-bit seeds need 50/75/99 rolls ' '(the Coldcard convention). A short count would silently weaken the seed.', []), - ('K4', 'Dice', 'MixZeroEntropyVector', - 'Mix known-answer vector (zero entropy)', - 'SHA256(0x00*32 || "123456") against a hardcoded digest. Pins the mix construction so a ' - 'refactor cannot quietly change how dice enter the seed.', - []), - ('K5', 'Dice', 'MixNonZeroEntropyVector', - 'Mix known-answer vector (non-zero entropy)', - 'Same construction with a non-zero starting entropy buffer, pinned to a hardcoded digest.', - []), - ('K6', 'Dice', 'MixDependsOnRolls', - 'Different rolls produce different entropy', - 'Two mixes differing only in the final roll must diverge. Catches a mix that ignores its ' - 'roll argument -- the failure mode where dice appear to work and contribute nothing.', - []), - ('K7', 'Dice', 'MixUsesExactCount', + ('K4', 'Dice', 'DeriveOnlyIsPlainSha256OfRolls', + 'DICE ONLY known-answer vector', + 'seed = SHA256("123456") against a digest computed in Python from the published formula, ' + 'not captured from this code. Pins the derivation to Coldcard\'s Dice-Rolls-Only byte ' + 'for byte, so a refactor cannot quietly change what a user must recompute offline.', + []), + ('K5', 'Dice', 'DeriveMixedVector', + 'MIXED known-answer vector', + 'seed = SHA256d("KK\\x01SM" || 0x00..0x1f || SHA256("KK\\x01D" || "654321165243")) against a ' + 'Python-computed digest. Pins the tag bytes, hash order and double-SHA of the mixed ' + 'derivation -- the exact formula tools/verify_dice_seed.py implements.', + []), + ('K5b', 'Dice', 'DeriveMixedZeroDeviceVector', + 'MIXED known-answer vector (zero device draw)', + 'Same construction with an all-zero device draw, pinned to a Python-computed digest.', + []), + ('K5c', 'Dice', 'DeriveMixedAliasesInPlace', + 'MIXED derives safely into its own input buffer', + 'reset.c derives into the buffer the device draw lives in. In-place and separate-output ' + 'results must be identical, or the aliasing would corrupt the seed.', + []), + ('K6', 'Dice', 'DeriveMixedDiffersFromUntaggedMix', + 'Tagged derivation cannot collide with the old formula', + 'The MIXED seed for zero draw and "123456" must differ from SHA256(draw || rolls), the ' + 'derivation earlier firmware used, so a wallet is never silently re-derived under the ' + 'wrong formula.', + []), + ('K7', 'Dice', 'DeriveOnlyUsesExactCount', 'Only the counted rolls contribute', 'Bytes past the declared roll count must not affect the result, so uninitialized tail ' 'bytes of the roll buffer can never leak into seed material.', []), + ('K7b', 'Dice', 'BiasGateIsThirtyPercentPerFace', + 'Loaded-die gate threshold', + 'Coldcard\'s rule: any face over 30% of the rolls is refused. 30/99 fails, 29/99 passes; ' + '16/50 fails, 15/50 (exactly 30%) passes.', + []), + ('K7c', 'Dice', 'BiasGateRejectsNonDiceBytes', + 'Non-d6 bytes are refused', + 'A byte outside \'1\'-\'6\' anywhere inside the counted rolls is refused regardless of the ' + 'distribution of the rest.', + []), ('K8', 'Storage', 'PinKdfRewrapsToActiveVersionAfterCorrectPin', 'Correct PIN unlocks and rewraps to the ACTIVE KDF', 'The migration path for the hardened PIN KDF: an existing device must still unlock with ' @@ -1102,7 +1175,8 @@ def _arg_shown(a): ['Approval screen']), ('E11', 'test_msg_signtx_ethereum_erc20', 'test_approve_all', 'ERC-20 approve unlimited', - 'MAX_UINT256 approval. Device shows "UNLIMITED" warning since this grants infinite spending.', + 'MAX_UINT256 approval. Older firmware showed an "UNLIMITED" warning; 7.14.2 and later ' + 'refuse it before drawing a confirmation screen.', ['Unlimited approval warning']), ('E12', 'test_msg_ethereum_makerdao', 'test_generate', 'MakerDAO generate DAI', 'Complex DeFi contract interaction (MakerDAO CDP).', []), @@ -1138,11 +1212,11 @@ def _arg_shown(a): 'Failure on the wire.', []), ('E17', 'test_msg_ethereum_erc20_uniswap_liquidity', 'test_sign_uni_approve_liquidity_ETH', - 'Uniswap V2 LP-token approval', - 'Approves the Uniswap V2 FOX/WETH LP token for the canonical router. The exact pool ' - 'identity and full-LP allowance are shown before the generic fee review, and the fixed ' - 'signature proves the reviewed transaction bytes are the bytes signed.', - ['Full LP allowance', 'LP token and pool address', 'Fee and final approval']), + 'Uniswap V2 unlimited LP-token approval refused', + 'Enables AdvancedMode, then attempts an unlimited FOX/WETH LP-token approval. ' + 'The device refuses it with Failure_ActionCancelled and the explicit disabled-approval ' + 'reason before any signing consent. The refusal itself is checked on the wire.', + ['Enable Policy: AdvancedMode']), ('E18', 'test_msg_ethereum_erc20_uniswap_liquidity', 'test_sign_uni_add_liquidity_ETH', 'Uniswap V2 add liquidity ETH+token', 'Clear-signs both desired/minimum FOX and ETH amounts, the signed recipient, and the ' @@ -1863,11 +1937,10 @@ def _arg_shown(a): # visual proof and is not. The per-beneficiary confirm screens are # captured by G35, which actually signs a two-beneficiary payout. []), - ('G37', 'test_msg_hive', 'test_hive_sign_ops_account_update2_rejects_authority_change', - 'account_update2 cannot rotate keys', - 'Only the profile-metadata form is in the table. Any owner/active/posting/memo_key ' - 'field present is a hard reject — the op-9/10 device-derived-keys invariant applied ' - 'field-level.', + ('G37', 'test_msg_hive', 'test_hive_sign_ops_account_update2_is_rejected', + 'account_update2 is refused', + 'Any owner/active/posting authority or memo_key present is a hard reject, so a key ' + 'change is never summarized as a profile-only update.', []), ('G38', 'test_msg_hive', 'test_hive_sign_ops_truncated_bodies_rejected', 'Truncated op bodies refused', @@ -2012,7 +2085,8 @@ def _arg_shown(a): # KKSOLSW1 -- the answer to S24. A v0 tx whose accounts live in a # lookup table cannot be resolved on-device, so today the device signs # accounts it never showed. These four are the additive invariant - # (section F) restated for Solana, and R-4.1 of SRS-7.15. + # (section F) restated for Solana, and R-4.1 of SRS-7.15. The + # canonical 7.15 product includes this protocol work. ('S26', 'test_msg_solana_lut_attestation', 'test_attested_accounts_are_shown_and_blind_sign_still_follows', 'Attested lookup-table accounts are shown, and the blind-sign warning survives', @@ -2048,7 +2122,52 @@ def _arg_shown(a): 'With no signer loaded a well-formed attestation is inert', 'Trust is opt-in and per-session. A perfectly valid attestation from a provider the ' 'user never loaded verifies against nothing and renders nothing, which is the ' - 'property that keeps 7.15 safe without any key-management programme.', + 'property that keeps sessions without a loaded provider safe.', + []), + # KKSOLSC1 v2, certified: the real SoltoshiDICE "Blackjack join" with the + # schema and SDICE token definition the deployed ClearSign Worker signs. + ('S30', 'test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_reviews_every_screen', + 'Certified SoltoshiDICE join: every value on screen, AdvancedMode OFF', + 'The real dapp transaction (legacy, no lookup tables), re-keyed so its fee payer ' + 'is this device. A 501-scope ClearSign root certificate authorizes the Vault ' + 'delegate that signed the join\'s schema and a KeepKeySolanaTokenDef/2 definition ' + 'of SDICE; neither signature covers a transaction. The certificate is issued by ' + 'the alpha root, which every 7.16+ build embeds, so a build that refuses it fails ' + 'rather than skips; production gets its own root after the 7.15 re-release. The ' + 'test reads the text of all 14 screens in ' + 'order: the compute-unit limit, the Transfer companion (funding account, then ' + '0.002 SOL to the session key), the certified signer, Round 86, Revision 980, ' + 'Seat 1, Buy-in / Allowance / Max wager as 1000.000000 SDICE with the full mint, ' + 'the session key, Expires in 1 h, and the sign prompt. It then verifies the ' + 'ed25519 signature over the message.', + ['Instr 1/3 compute unit limit', 'Instr 2/3 funding account', + 'Instr 2/3 send 0.002 SOL to session key', 'KeepKey ClearSign signer', + 'SoltoshiDICE Blackjack join', 'Round 86', 'Revision 980', 'Seat 1', + 'Buy-in 1000 SDICE + mint', 'Session key', 'Expires in 1 h', + 'Allowance 1000 SDICE + mint', 'Max wager 1000 SDICE + mint', + 'Sign this Solana transaction?']), + ('S31', 'test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_priority_fee_names_fee_payer', + 'Certified join with a priority fee names the fee payer', + 'The real join sets no compute-unit price, so it has no Fee screens. With a ' + 'SetComputeUnitPrice added, the same certified review ends with Fee payer ' + ' and Max priority fee 0.000200000 SOL before the sign prompt.', + []), + ('S32', 'test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_untrusted_definition_shows_base_units', + 'Certified join without a valid token definition shows base units', + 'Without the SDICE definition, the three amounts read 1000000000 base units of ' + 'mint with the full mint. A definition whose signature differs by one byte ' + 'gives exactly the same screens, frame for frame. No symbol, and no scaling, ' + 'comes from an unverified definition.', + []), + ('S33', 'test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_ignores_blind_sign_policy', + 'Certified join is not a blind sign when AdvancedMode is on', + 'Turning AdvancedMode on leaves the certified review identical, frame for frame, ' + 'and never adds the Blind Sign screen: the certificate, not the policy, decides ' + 'how the transaction is shown.', []), ]), @@ -2545,7 +2664,6 @@ def _arg_shown(a): 'again. MALFORMED is the assertion: the signer itself is gone.', ['Enable Policy: AdvancedMode', "Load Clearsigner: Trust 'CI Test' (fingerprint) ... NOT verified by KeepKey", - 'Home screen at the refusal - the AdvancedMode gate draws no screen of its own', 'Enable Policy: AdvancedMode (re-armed to isolate the slot)']), ('I5', 'test_msg_session_trust_lifetime', 'test_signer_dropped_by_power_cycle', 'Reboot drops the loaded signer', @@ -2575,7 +2693,6 @@ def _arg_shown(a): ['Enable Policy: AdvancedMode', "Load Clearsigner: Trust 'CI Test' (fingerprint) ... NOT verified by KeepKey", 'Disable Policy: AdvancedMode', - 'Home screen at the refusal - the metadata message fails closed with no screen', 'Enable Policy: AdvancedMode - the only confirm on re-arming, and the signer does NOT ' 'come back with it']), ]), @@ -2897,6 +3014,180 @@ def _arg_shown(a): []), ]), + ('ER', 'ERC-7730 v2 Certified Clear-Signing Conformance', '7.19.0', + 'ERC-7730 definitions are compiled into a bounded canonical program, authenticated by ' + 'KeepKey\'s certified delegation hierarchy, and interpreted against the exact calldata or ' + 'EIP-712 document being signed. The host supplies types, labels and formatting policy; it ' + 'never supplies authoritative decoded transaction values. A certified-definition failure ' + 'refuses signing and cannot silently downgrade to a less-specific certified display.', + [ + 'AUTHENTICATION AND REPLAY BOUNDARY:', + '- K773 envelope: version + purpose + canonical C773 program + sorted Merkle proof +', + ' 139-byte KeepKey delegation certificate + compact secp256k1 signature.', + '- Purpose digest: SHA256("KEEPKEY:ERC7730:CATALOG\\0" || catalog_root).', + '- Definition id commits to the complete envelope; offset-zero replay is re-hashed before', + ' staged interpreter output becomes authoritative.', + '- Catalog lookup binds kind, chain, target and selector/typeHash. Unknown, ambiguous,', + ' reordered, oversized and recursively repeated definitions fail closed.', + '', + 'CANONICAL PROGRAM AND DEVICE INTERPRETER:', + '- 179-byte header; sorted UTF-8 strings; canonical recursive ABI/EIP-712 node tree;', + ' typed structured/container/literal paths; typed literals and conditions;', + ' formatter, display, deployment/domain binding and resource sections.', + '- Recursive tuples and arrays through depth 12, 64 ABI nodes, 64 aggregate array', + ' elements, negative indices, half-open slices, nested array frames and separators.', + '- Display bytecode: intent, atomic interpolation fallback, fields, nested groups, arrays,', + ' embedded calls and explicit end; all forward/back links and depth are recomputed.', + '- Conditions: always, never, optional, empty/not-empty, in/not-in and must-match.', + '- Formatters: raw, native/token amounts, NFT, date, duration, unit, enum, chain, address', + ' name, ticker, ERC-7930 interoperable address, embedded calldata and encrypted fallback.', + '- Signed token/network records establish ticker, decimals and native currency. Live', + ' results may annotate but cannot replace a device-decoded value.', + '', + 'REAL-WORLD AND EXHAUSTIVE EVIDENCE:', + '- Exact KeepKey SDK THORChain router deposit calldata, including vault, asset, amount and', + ' memo, is selector-bound and firmware-validated.', + '- Official Uniswap Router02 signed transaction and Permit2 typed-data fixtures bind the', + ' expected selector, target, chain, typeHash and domain constraints.', + '- Every one of 1,450 calldata formats exposed after bounded include expansion in the', + ' official ERC-7730 registry compiles and reaches the firmware catalog verifier.', + '- Deep ParaSwap Augustus multiSwap/megaSwap definitions exercise depths 9 and 11 while', + ' the compacted signing workflow remains exactly 4,096 bytes of fixed SRAM.', + '- The SDK/Vault consumer path accepts the same signed catalog on ethSignTransaction and', + ' from Relay/ShapeShift quote payloads, preserves it through swap construction, preloads', + ' the primary envelope, and answers device-driven definition requests in 1,024-byte', + ' chunks. Missing, malformed, mismatched, oversized and over-depth requests abort.', + '- Consumer evidence: hdwallet PR #3 passed build/lint and 8 focused catalog/policy tests;', + ' keepkey-vault PR #444 passed 59 focused REST schema and real Relay swap parser tests,', + ' Linux/macOS release builds and the packaged Intel macOS smoke test before merge.', + '- Device evidence: 133 focused firmware tests pass: ABI (5), streamed ABI (7), catalog', + ' (19), conditions (6), canonical EIP-712 (33), formatting (8), program readers (20),', + ' transaction continuation (3), and authenticated workflow execution (32).', + '- Host evidence: 25 focused python-keepkey tests pass for deterministic compilation,', + ' official-registry traversal, signed envelopes, request policy and protobuf transport.', + '', + 'COMPLETE ACTIVE-V2 SUPPORT BREAKDOWN:', + '- Descriptor/context: schema-major enforcement; bounded includes and deterministic merge;', + ' owner/info/constants/maps/enums; canonical selector and EIP-712 encodeType/typeHash;', + ' exact chain/deployment/domain/contract/selector binding; unknown selectors refuse.', + '- ABI/value model: every legal int width; address/bool/bytesN/bytes/string; fixed and', + ' dynamic arrays; static/dynamic tuples; depth-12 recursion; negative index, full-array', + ' and bounded-slice paths; transaction, structured and literal containers.', + '- References: #/$/@ names, fields, groups, constants, maps, enums, tokens and networks are', + ' host-resolved to typed canonical ids; the device rechecks type, range and section links.', + '- Display: string/object intents, atomic interpolated intent fallback, ordered fields,', + ' recursive groups, authenticated array iteration and separators.', + '- Visibility/assertions: always, never, empty, not-empty, in, not-in and must-match;', + ' condition operands are captured from device-decoded calldata or streamed typed data.', + '- Formatting: raw integer/string/bytes/address; native/token amounts and thresholds; NFT;', + ' date, duration, unit, enum, chain id, trusted-name fallback, ticker and ERC-7930.', + '- Nested/special: embedded calldata requests a separately certified definition with a', + ' depth-4/cycle boundary; encrypted data never claims plaintext without verified proof;', + ' ERC-4337/EIP-5792 shapes are handled as ordinary bounded EIP-712 structs/arrays.', + '- Failure policy: dirty padding, gaps/overlap/trailing bytes, bad offsets, wrong context,', + ' missing definitions, invalid proof/certificate/purpose, resource excess, ambiguity and', + ' host/device value conflicts all refuse signing; certified failure never downgrades.', + '', + 'LIMIT OF THIS SECTION: catalog-verifier success ends at the expected UNTRUSTED result', + 'when tests use a synthetic certificate. A trusted-success emulator capture additionally', + 'requires a certificate issued by the KeepKey root for the test delegate.', + ], + [ + ('ER1', 'test_erc7730_compiler', + 'test_official_registry_all_calldata_formats_reach_firmware', + 'All 1,450 official calldata formats reach firmware', + 'Recursively merges bounded includes, compiles every applicable registry format and ' + 'feeds each complete canonical program through the firmware catalog verifier.', []), + ('ER2', 'test_erc7730_compiler', + 'test_compiles_and_checks_exact_keepkey_sdk_thorchain_swap', + 'Exact KeepKey SDK THORChain swap fixture', + 'Checks selector, vault, asset, amount, dynamic memo and transaction value before ' + 'firmware validation.', []), + ('ER3', 'test_erc7730_compiler', + 'test_compiles_official_uniswap_tuple_fixture_through_firmware', + 'Official Uniswap signed transaction', + 'Binds the real Router02 target, chain, selector and published transaction hash.', []), + ('ER4', 'test_erc7730_compiler', + 'test_compiles_official_uniswap_eip712_fixture_through_firmware', + 'Official Permit2 EIP-712 fixture', + 'Proves canonical encodeType/typeHash, domain constraints and signed token/network ' + 'metadata reach the firmware parser.', []), + ('ER5', 'test_erc7730_compiler', + 'test_loads_bounded_includes_and_compiles_array_backed_group', + 'References, includes and grouped arrays', + 'Exercises deterministic include merge, shared field references and a group executed ' + 'inside an authenticated array frame.', []), + ('ER6', 'test_erc7730_compiler', + 'test_compiles_recursive_array_iteration_frames', + 'Recursive ABI arrays and separators', + 'Builds nested array begin/end links and validates their declared resource depth.', []), + ('ER7', 'test_erc7730_compiler', + 'test_compiles_interpolated_intent_and_metadata_enum', + 'Atomic interpolation and enum maps', + 'Every interpolated operand is also an unconditional field; failure selects the ' + 'fallback intent atomically.', []), + ('ER8', 'test_erc7730_compiler', + 'test_compiles_typed_if_not_in_and_must_match_conditions', + 'Typed visibility and must-match conditions', + 'Typed literal sets control visibility; must-match is a signing assertion.', []), + ('ER9', 'test_erc7730_catalog', + 'test_signed_catalog_envelope_commits_program_proof_and_certificate', + 'Certified Merkle catalog envelope', + 'Verifies deterministic root construction, purpose digest, signature and exact wire ' + 'layout.', []), + ('ER10', 'test_erc7730_catalog', + 'test_catalog_refuses_unknown_ambiguous_and_malformed_requests', + 'Catalog lookup fails closed', + 'Unknown selectors, oversized chunks, excessive recursion and ambiguous tuples are ' + 'rejected.', []), + ('ER11', 'test_erc7730_protocol_bindings', + 'test_definition_chunk_round_trip_is_byte_exact', + 'Canonical protocol transport is byte exact', + 'Protobuf bindings preserve definition id, offsets, total length and envelope bytes.', []), + ('ER12', 'test_erc7730_compiler', + 'test_token_amount_without_token_uses_firmware_raw_fallback', + 'Unknown tokens never become trusted labels', + 'A missing token reference displays the device-decoded raw integer and forbids ' + 'token-specific auxiliary metadata.', []), + ('ER13', 'test_erc7730_compiler', + 'test_parses_recursive_tuple_and_array_signature', + 'Canonical recursive ABI signature parsing', + 'Parses nested tuple and array fragments into the exact bounded forward tree consumed by ' + 'the firmware interpreter.', []), + ('ER14', 'test_erc7730_compiler', + 'test_compiles_deterministic_canonical_calldata_program', + 'Compilation is byte-for-byte deterministic', + 'Equivalent descriptor input produces one canonical program, selector and source-binding ' + 'identity rather than host-dependent wire bytes.', []), + ('ER15', 'test_erc7730_compiler', + 'test_compiles_array_iteration_separator_and_optional_visibility', + 'Array iteration, separators and optional visibility', + 'Compiles array-backed fields with authenticated length, separator control flow and ' + 'ifEmpty/ifNotEmpty behavior.', []), + ('ER16', 'test_erc7730_compiler', + 'test_compiles_nested_field_group_with_balanced_links', + 'Recursive groups have balanced control flow', + 'Every group call/return and display-program forward link is recomputed and bounded.', []), + ('ER17', 'test_erc7730_catalog', + 'test_catalog_serves_exact_lookup_and_id_replays', + 'Exact-context lookup and authenticated replay', + 'Serves only the requested identity tuple and re-authenticates offset-zero definition-id ' + 'replays before interpreter output becomes authoritative.', []), + ('ER18', 'test_erc7730_catalog', + 'test_preload_streams_and_checks_every_acknowledgement', + 'Preload transport checks every acknowledgement', + 'Streams bounded chunks and refuses reordered, missing or mismatched device acknowledgements.', []), + ('ER19', 'test_erc7730_protocol_bindings', + 'test_erc7730_message_ids_and_mapping', + 'Canonical message ids are stable', + 'Pins request, chunk and acknowledgement messages to the canonical protocol mapping.', []), + ('ER20', 'test_erc7730_protocol_bindings', + 'test_lookup_kinds_encode_expected_context', + 'Every definition kind carries its security context', + 'Calldata, EIP-712, token and network lookups encode only their required chain, target, ' + 'selector or type-hash identity fields.', []), + ]), + # Two-character id because all 26 letters were taken. The catalog keys on a # string, not a char, so this costs nothing. ('TD', 'Structured EIP-712 - The Device Reads The Document', '7.15.0', @@ -2965,6 +3256,37 @@ def _arg_shown(a): ] +# A section may span adjacent release lines even when individual native tests +# landed later. Filter those rows before validation so a 7.14.3 report cannot +# demand 7.15-only binaries, while 7.15 still requires the coverage. +_TEST_MIN_VERSION = { + ('Storage', 'PinKdfRewrapsToActiveVersionAfterCorrectPin'): '7.15.0', + ('Storage', 'PinUnlocksAfterRebootUnderV17'): '7.15.0', + ('Storage', 'PinKdfV2FlagIsVersionedInV19'): '7.15.0', + ('test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_reviews_every_screen'): '7.16.0', + ('test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_priority_fee_names_fee_payer'): '7.16.0', + ('test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_untrusted_definition_shows_base_units'): '7.16.0', + ('test_msg_solana_schema_v2', + 'test_certified_soltoshi_join_ignores_blind_sign_policy'): '7.16.0', +} + + +def _active_sections(fw_version): + active = [] + for letter, title, minimum, background, flow, tests in SECTIONS: + if not ver_ge(fw_version, minimum): + continue + filtered = [ + test for test in tests + if ver_ge(fw_version, + _TEST_MIN_VERSION.get((test[1], test[2]), minimum)) + ] + active.append((letter, title, minimum, background, flow, filtered)) + return active + # --------------------------------------------------------------- # Render # --------------------------------------------------------------- @@ -2996,7 +3318,7 @@ def render(output_path, fw_version, results, screenshot_dir=None): _build_frame_census(screenshot_dir) ts = datetime.now().strftime('%Y-%m-%d %H:%M') build_label = os.environ.get('KK_BUILD_LABEL', '').strip() - active = [(l,t,mf,bg,fl,tests) for l,t,mf,bg,fl,tests in SECTIONS if ver_ge(fw_version, mf)] + active = _active_sections(fw_version) # Separate specs section (no tests) from test sections specs = [s for s in active if not s[5]] @@ -3106,6 +3428,7 @@ def _section_state(s): pb.text(9, f'Tests: {len(tests)}', bold=True) pb.gap(2) for tid, mod, meth, title, ctx, scr in tests: + scr = _screens_for(fw_version, mod, meth, scr) pb.need(50) r = _lookup(results, mod, meth) pb.check(9, f'{tid} {meth}', r) @@ -3217,16 +3540,27 @@ def screenshot_filter(fw_version): The shell script calls this instead of maintaining a hardcoded filter. Adding screenshots to a test in SECTIONS automatically includes it in CI Phase 1. """ - active = [(l,t,mf,bg,fl,tests) for l,t,mf,bg,fl,tests in SECTIONS if ver_ge(fw_version, mf)] + active = _active_sections(fw_version) terms = [] for letter, title, mf, bg, fl, tests in active: for tid, mod, meth, ttl, ctx, scr in tests: - if scr: # non-empty screenshot list = needs OLED capture + if _screens_for(fw_version, mod, meth, scr): # Use (method and module) for unambiguous pytest -k matching terms.append(f'({meth} and {mod})') return ' or '.join(terms) +def screenshot_test_list(fw_version): + """Return exact module::method selectors consumed by conftest.py.""" + active = _active_sections(fw_version) + pairs = set() + for _letter, _title, _mf, _bg, _fl, tests in active: + for _tid, mod, meth, _ttl, _ctx, screens in tests: + if _screens_for(fw_version, mod, meth, screens): + pairs.add('%s::%s' % (mod, meth)) + return '\n'.join(sorted(pairs)) + + # Modules whose tests must actually RUN once the firmware is new enough to be # catalogued for them -- a skip is a failure, not a waiver. # @@ -3240,8 +3574,14 @@ def screenshot_filter(fw_version): # version-blind set would fail every older-firmware run for a module that # legitimately cannot exist yet. MUST_RUN_MODULES = { - 'test_msg_signtx_taproot': '7.0.0', - 'test_msg_getaddress_taproot': '7.0.0', + # Taproot did not exist at 7.0.0. That floor only ever held because this + # table was applied to products that happen to carry taproot: 7.14.2 + # reports no supports_taproot and has no P2TR path in signing.c at all, so + # requiring its six taproot cases to run demanded coverage the product + # cannot have. The floor is the release taproot actually ships in, which + # keeps the requirement binding on 7.14.3 and 7.15, both of which carry it. + 'test_msg_signtx_taproot': '7.14.3', + 'test_msg_getaddress_taproot': '7.14.3', # GH #516: all three Uniswap liquidity tests used to skip together on the # emulator, leaving a daily-driver signing path completely unexercised. 'test_msg_ethereum_erc20_uniswap_liquidity': '7.16.0', @@ -3286,11 +3626,11 @@ def screenshot_audit(fw_version, screenshot_root, junit_path=None): mod = next((p for p in cn.split('.') if p.startswith('test_')), '') skipped.add((mod, tc.get('name'))) - active = [x for x in SECTIONS if ver_ge(fw_version, x[2])] + active = _active_sections(fw_version) missing = [] for letter, title, mf, bg, fl, tests in active: for tid, mod, meth, ttl, ctx, scr in tests: - if not scr: + if not _screens_for(fw_version, mod, meth, scr): continue if (mod, meth) in skipped: continue @@ -3302,7 +3642,7 @@ def screenshot_audit(fw_version, screenshot_root, junit_path=None): return (len(missing) == 0, missing) -def validate_junit(fw_version, results, build_variant='full'): +def validate_junit(fw_version, results, variant='full'): """Check SECTIONS tests against JUnit results. Returns (passed, failed_list). A test is considered failed if it appears in SECTIONS for this firmware version @@ -3311,17 +3651,19 @@ def validate_junit(fw_version, results, build_variant='full'): Tests that were skipped (gated by requires_message/requires_firmware) are OK, unless their module is in MUST_RUN_MODULES. """ - active = [(l,t,mf,bg,fl,tests) for l,t,mf,bg,fl,tests in SECTIONS if ver_ge(fw_version, mf)] + active = _active_sections(fw_version) failures = [] for letter, title, mf, bg, fl, tests in active: for tid, mod, meth, ttl, ctx, scr in tests: status = _lookup(results, mod, meth) if status in ('fail', 'error'): failures.append((tid, mod, meth, status)) - elif (status == 'skip' - and ver_ge(fw_version, MUST_RUN_MODULES.get(mod, '99.0.0')) - and not (build_variant == 'bitcoin-only' - and mod in FULL_FEATURE_ONLY_MUST_RUN_MODULES)): + must_run = not ( + variant == 'bitcoin-only' and + mod in FULL_FEATURE_ONLY_MUST_RUN_MODULES + ) + if (status == 'skip' and must_run and + ver_ge(fw_version, MUST_RUN_MODULES.get(mod, '99.0.0'))): failures.append((tid, mod, meth, 'skipped-but-required')) elif not status: failures.append((tid, mod, meth, 'missing')) @@ -3329,6 +3671,7 @@ def validate_junit(fw_version, results, build_variant='full'): def main(): + global SECTIONS p = argparse.ArgumentParser(description='KeepKey Firmware Test Report') p.add_argument('--output', default='test-report.pdf') p.add_argument('--fw-version', default=None) @@ -3340,12 +3683,37 @@ def main(): help='JUnit XML for --screenshot-audit, so skipped tests are not counted missing') p.add_argument('--screenshot-filter', action='store_true', help='Print pytest -k expression for tests needing screenshots, then exit') + p.add_argument('--screenshot-test-list', action='store_true', + help='Print exact module::method screenshot selectors, then exit') p.add_argument('--validate-junit', action='store_true', help='Validate JUnit results against SECTIONS, exit non-zero on failures') - p.add_argument('--build-variant', choices=('full', 'bitcoin-only'), default='full', - help='Expected CI product; controls only explicit build-flag waivers') + # --build-variant is the spelling firmware CI (python-keepkey-tests.sh) + # passes; keep it as an alias so either repo can move first. + p.add_argument('--variant', '--build-variant', dest='variant', + choices=('full', 'bitcoin-only'), + default=os.environ.get('KK_FIRMWARE_VARIANT', 'full'), + help='Product variant whose required report coverage is validated') + p.add_argument('--section', action='append', default=[], + help='Render only the named section id (repeatable)') + p.add_argument('--firmware-sha', default=None, + help='Exact firmware commit represented by this report') + p.add_argument('--python-sha', default=None, + help='Exact python-keepkey commit represented by this report') + p.add_argument('--run-url', default=None, + help='Exact CI run that produced the evidence') + p.add_argument('--generator-sha256', default=None, + help='Combined wrapper/renderer digest') + p.add_argument('--arm-manifest-sha256', default=None, + help='Digest binding the complete ARM manifest set') args = p.parse_args() + if args.section: + wanted = set(args.section) + SECTIONS = [section for section in SECTIONS if section[0] in wanted] + missing = wanted.difference(section[0] for section in SECTIONS) + if missing: + p.error('unknown section(s): %s' % ', '.join(sorted(missing))) + fw = args.fw_version if not fw: print('Detecting firmware from emulator...', file=sys.stderr) @@ -3366,13 +3734,16 @@ def main(): if args.screenshot_filter: print(screenshot_filter(fw)) sys.exit(0) + if args.screenshot_test_list: + print(screenshot_test_list(fw)) + sys.exit(0) if args.validate_junit: if not args.junit: print('ERROR: --validate-junit requires --junit=', file=sys.stderr) sys.exit(2) results = parse_junit(args.junit) - ok, failures = validate_junit(fw, results, args.build_variant) + ok, failures = validate_junit(fw, results, args.variant) if ok: print(f'SECTIONS validation passed: all tests for fw {fw} are pass or skip') sys.exit(0) @@ -3382,6 +3753,17 @@ def main(): print(f' {tid} {mod}::{meth} -> {status}') sys.exit(1) + provenance = [ + ('firmware', args.firmware_sha), + ('python', args.python_sha), + ('run', args.run_url), + ('generator', args.generator_sha256), + ('arm-manifests', args.arm_manifest_sha256), + ] + supplied = ['%s=%s' % item for item in provenance if item[1]] + if supplied: + os.environ['KK_BUILD_LABEL'] = ' | '.join(supplied) + results = parse_junit(args.junit) if args.junit else {} render(args.output, fw, results, args.screenshots) diff --git a/setup.py b/setup.py index 655d9b35..b665be69 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ test_suite='tests/**/test_*.py', install_requires=[ 'ecdsa>=0.9', - 'protobuf>=3.20.0', + 'protobuf>=3.17,<4', 'mnemonic>=0.8', 'hidapi>=0.7.99.post15', 'libusb1>=1.6' diff --git a/tests/common.py b/tests/common.py index cee22b51..b0382f62 100644 --- a/tests/common.py +++ b/tests/common.py @@ -30,9 +30,32 @@ from keepkeylib.client import KeepKeyClient, KeepKeyDebuglinkClient, KeepKeyDebuglinkClientVerbose from keepkeylib import tx_api -tx_api.cache_dir = 'txcache' +TX_FIXTURE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'txcache') +tx_api.configure_offline_fixtures(TX_FIXTURE_DIR) VERBOSE = False + +def reset_screenshot_capture(client): + """Start a fresh evidence sequence after fixture-only device setup. + + KeepKeyTest.setUp() wipes the device and the setup_mnemonic_* helpers load + a public test seed. Those confirmations are prerequisites, not evidence + for the test that follows. Leaving them in the per-test directory allowed + a Wipe/import/lock frame to satisfy an unrelated OLED requirement. + """ + if os.environ.get('KEEPKEY_SCREENSHOT') != '1': + return + screenshot_dir = getattr(client, 'screenshot_dir', None) + if not screenshot_dir: + raise RuntimeError('screenshot capture has no per-test directory') + os.makedirs(screenshot_dir, exist_ok=True) + for name in os.listdir(screenshot_dir): + if (name.startswith('btn') and name.endswith('.png') and + len(name) == len('btn00000.png')) or name == 'frames.json': + os.unlink(os.path.join(screenshot_dir, name)) + client.screenshot_id = 0 + class KeepKeyTest(unittest.TestCase): def setUp(self): transport = config.TRANSPORT(*config.TRANSPORT_ARGS, **config.TRANSPORT_KWARGS) @@ -75,11 +98,7 @@ def setUp(self): self.pin8 = '45678978' self.client.wipe_device() - # The wipe confirmation belongs to the test harness, not the test. - # Drop it for every suite, including suites that never call one of the - # setup_mnemonic_* helpers; otherwise a presence-only screenshot audit - # can mistake this frame for evidence of the behavior under test. - self._drop_setup_screenshots() + reset_screenshot_capture(self.client) if VERBOSE: print("Setup finished") @@ -94,24 +113,27 @@ def _drop_setup_screenshots(self): def setup_mnemonic_allallall(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic_all, pin='', passphrase_protection=False, label='test', language='english') - self._drop_setup_screenshots() + reset_screenshot_capture(self.client) def setup_mnemonic_abandon(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic_abandon, pin='', passphrase_protection=False, label='test', language='english') - self._drop_setup_screenshots() + reset_screenshot_capture(self.client) def setup_mnemonic_nopin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin='', passphrase_protection=False, label='test', language='english') - self._drop_setup_screenshots() + reset_screenshot_capture(self.client) def setup_mnemonic_vuln20007(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic20007, pin='', passphrase_protection=False, label='test', language='english') + reset_screenshot_capture(self.client) def setup_mnemonic_pin_nopassphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=False, label='test', language='english') + reset_screenshot_capture(self.client) def setup_mnemonic_pin_passphrase(self): self.client.load_device_by_mnemonic(mnemonic=self.mnemonic12, pin=self.pin4, passphrase_protection=True, label='test', language='english') + reset_screenshot_capture(self.client) def tearDown(self): self.client.close() @@ -125,11 +147,19 @@ def assertEqual(self, lhs, rhs): def assertEndsWith(self, s, suffix): self.assertTrue(s.endswith(suffix), "'{}'.endswith('{}')".format(s, suffix)) - def requires_firmware(self, ver_required): + def firmware_version(self): self.client.init_device() features = self.client.features version = "%s.%s.%s" % (features.major_version, features.minor_version, features.patch_version) - if semver.VersionInfo.parse(version) < semver.VersionInfo.parse(ver_required): + return semver.VersionInfo.parse(version) + + def firmware_at_least(self, ver_required): + """Return whether the connected firmware includes a versioned feature.""" + return self.firmware_version() >= semver.VersionInfo.parse(ver_required) + + def requires_firmware(self, ver_required): + version = self.firmware_version() + if version < semver.VersionInfo.parse(ver_required): self.skipTest("Firmware version " + ver_required + " or higher is required to run this test") def requires_taproot(self): @@ -144,6 +174,19 @@ def requires_taproot(self): if not getattr(self.client.features, 'supports_taproot', False): self.skipTest("Firmware does not report supports_taproot") + def requires_dice_modes(self): + """Skip unless the firmware reports the verifiable dice modes. + + A capability, not a version. Firmware without the unit skips the + unknown ResetDevice.dice_only field and runs the older ceremony, so a + version gate would fail these tests red on such a build -- and a host + must refuse to offer the modes on exactly this same signal, because + that older firmware would derive a different wallet without complaint. + """ + self.client.init_device() + if not getattr(self.client.features, 'supports_dice_modes', False): + self.skipTest("Firmware does not report supports_dice_modes") + def requires_structured_eip712(self): """Skip unless the FIRMWARE drives the structured EIP-712 walk. @@ -250,4 +293,3 @@ def requires_bitcoinOnly(self): "EmulatorBTC"): self.skipTest("Bitcoin-only firmware required to run this test") - diff --git a/tests/conftest.py b/tests/conftest.py index 6d9aeade..837a2d68 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,8 +2,8 @@ conftest.py -- pytest plugin for per-test OLED screenshot directories. When KEEPKEY_SCREENSHOT=1, patches KeepKeyTest.setUp to set per-test -screenshot directories BEFORE setUp runs (so wipe_device captures go -to the right place). +screenshot directories. Fixture-only wipe/import captures are cleared before +the test action begins, so they cannot masquerade as the test's OLED evidence. FAIL-FAST: If KEEPKEY_SCREENSHOT=1 and zero PNGs are captured after all tests complete, the session exits non-zero. This prevents silent @@ -12,7 +12,83 @@ import pytest import os import glob +import hashlib +import json +import shutil +import socket import sys +from urllib.parse import urlparse + +import requests + + +def pytest_collection_modifyitems(config, items): + """Select exact report test IDs for the screenshot-only pytest phase.""" + if os.environ.get('KEEPKEY_SCREENSHOT') != '1': + return + encoded = os.environ.get('KEEPKEY_SCREENSHOT_TESTS', '') + if not encoded: + raise pytest.UsageError( + 'KEEPKEY_SCREENSHOT_TESTS must list exact module::method pairs') + selected_pairs = set() + for line in encoded.splitlines(): + if not line: + continue + parts = line.split('::') + if len(parts) != 2 or not all(parts): + raise pytest.UsageError( + 'invalid KEEPKEY_SCREENSHOT_TESTS entry %r' % line) + selected_pairs.add(tuple(parts)) + selected = [] + deselected = [] + for item in items: + module = os.path.splitext(os.path.basename(item.location[0]))[0] + method = getattr(item, 'originalname', None) or item.name.split('[', 1)[0] + if (module, method) in selected_pairs: + selected.append(item) + else: + deselected.append(item) + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = selected + + +def _screenshot_dir_for_item(item): + module = os.path.splitext(os.path.basename(item.location[0]))[0] + method = getattr(item, 'originalname', None) or item.name.split('[', 1)[0] + return os.path.join( + os.environ.get('SCREENSHOT_DIR', 'screenshots'), + module.replace('test_', '', 1), method) + + +def _remove_skipped_screenshot_evidence(item): + """Delete every frame captured before a test became skipped. + + Kept as a small named boundary so the release mutation controls can plant + fixture residue and prove that this exact cleanup still runs fail-closed. + """ + path = _screenshot_dir_for_item(item) + try: + shutil.rmtree(path) + except FileNotFoundError: + return + if os.path.lexists(path): + raise OSError('screenshot directory still exists after cleanup: %s' % + path) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item, call): + """A skipped case must never retain setup/policy frames as evidence.""" + outcome = yield + report = outcome.get_result() + if (os.environ.get('KEEPKEY_SCREENSHOT') == '1' and report.skipped): + try: + _remove_skipped_screenshot_evidence(item) + except OSError as exc: + raise RuntimeError( + 'failed to remove skipped OLED evidence for %s: %s' % + (item.nodeid, exc)) if os.environ.get('KEEPKEY_SCREENSHOT') == '1': import common @@ -20,8 +96,8 @@ _orig_setUp = common.KeepKeyTest.setUp def _patched_setUp(self): - # Derive per-test screenshot directory BEFORE setUp runs, - # so captures during wipe_device/load_device go to the right place. + # Derive the per-test directory before setUp. common.KeepKeyTest.setUp + # clears fixture-only frames after its initial wipe completes. test_id = self.id() # pytest: "tests.test_msg_wipedevice.TestDeviceWipe.test_wipe_device" # unittest: "test_msg_wipedevice.TestDeviceWipe.test_wipe_device" @@ -51,6 +127,94 @@ def _patched_setUp(self): common.KeepKeyTest.setUp = _patched_setUp +def _configured_emulator_endpoints(getaddrinfo): + """Return the exact UDP names and addresses configured by the test harness.""" + names = set() + addresses = set() + for variable, default in ( + ('KK_TRANSPORT_MAIN', '127.0.0.1:11044'), + ('KK_TRANSPORT_DEBUG', '127.0.0.1:11045')): + endpoint = os.environ.get(variable, default) + try: + host, port_text = endpoint.rsplit(':', 1) + port = int(port_text) + except (AttributeError, TypeError, ValueError): + raise RuntimeError( + '%s must be a host:port UDP emulator endpoint, got %r' % + (variable, endpoint)) + names.add((host, port)) + for result in getaddrinfo(host, port, type=socket.SOCK_DGRAM): + sockaddr = result[4] + addresses.add((sockaddr[0], sockaddr[1])) + return names, addresses + + +@pytest.fixture(autouse=True) +def deny_external_network(monkeypatch, request): + """Allow only local sockets and the harness's exact UDP emulator endpoints.""" + from emulator_endpoints import is_owned_endpoint + + nodeid = request.node.nodeid + original_getaddrinfo = socket.getaddrinfo + original_connect = socket.socket.connect + original_connect_ex = socket.socket.connect_ex + original_sendto = socket.socket.sendto + emulator_names, emulator_addresses = _configured_emulator_endpoints( + original_getaddrinfo) + + def denied(destination): + raise AssertionError( + 'authoritative test attempted external network access: ' + 'test=%s destination=%r' % (nodeid, destination)) + + def guarded_getaddrinfo(host, *args, **kwargs): + port = args[0] if args else kwargs.get('port') + if (host, port) not in emulator_names and not is_owned_endpoint((host, port)): + denied((host, port)) + return original_getaddrinfo(host, *args, **kwargs) + + def allowed_socket_address(sock, address): + if not isinstance(address, tuple) or len(address) < 2: + return False + # No Unix sockets, TCP loopback, or arbitrary localhost ports. The + # authoritative suite may talk only to the two exact UDP transports + # configured for this emulator run, plus explicit test-owned leases. + if sock.family not in (socket.AF_INET, socket.AF_INET6): + return False + if (sock.type & 0x0f) != socket.SOCK_DGRAM: + return False + endpoint = (address[0], address[1]) + return (endpoint in emulator_names or endpoint in emulator_addresses + or is_owned_endpoint(endpoint)) + + def guarded_connect(sock, address): + if not allowed_socket_address(sock, address): + denied(address) + return original_connect(sock, address) + + def guarded_connect_ex(sock, address): + if not allowed_socket_address(sock, address): + denied(address) + return original_connect_ex(sock, address) + + def guarded_sendto(sock, data, *args): + address = args[-1] + if not allowed_socket_address(sock, address): + denied(address) + return original_sendto(sock, data, *args) + + def guarded_request(session, method, url, *args, **kwargs): + raise AssertionError( + 'authoritative test attempted HTTP access: test=%s method=%s ' + 'url=%s' % (nodeid, method, url)) + + monkeypatch.setattr(socket, 'getaddrinfo', guarded_getaddrinfo) + monkeypatch.setattr(socket.socket, 'connect', guarded_connect) + monkeypatch.setattr(socket.socket, 'connect_ex', guarded_connect_ex) + monkeypatch.setattr(socket.socket, 'sendto', guarded_sendto) + monkeypatch.setattr(requests.sessions.Session, 'request', guarded_request) + + def pytest_sessionfinish(session, exitstatus): """Fail-fast: if screenshots were requested but none captured, fail the session.""" if os.environ.get('KEEPKEY_SCREENSHOT') != '1': @@ -61,5 +225,53 @@ def pytest_sessionfinish(session, exitstatus): if count == 0: print("FATAL: KEEPKEY_SCREENSHOT=1 but 0 PNGs captured. Screenshot pipeline is broken.", file=sys.stderr) session.exitstatus = 1 - else: - print("[SCREENSHOT] Session complete: %d PNGs captured" % count, file=sys.stderr) + return + + try: + sequence_count = 0 + for directory, _subdirs, files in os.walk(screenshot_dir): + if not any(name.endswith('.png') for name in files): + if 'frames.json' in files: + raise AssertionError( + 'frame manifest has no PNG sequence: %s' % directory) + continue + other = sorted(name for name in files + if name != 'frames.json') + expected = ['btn%05d.png' % i for i in range(len(other))] + if other != expected: + raise AssertionError( + 'non-contiguous or unexpected OLED frames in %s: ' + 'found=%r expected=%r' % (directory, other, expected)) + frames = [] + for name in expected: + path = os.path.join(directory, name) + with open(path, 'rb') as handle: + digest = hashlib.sha256(handle.read()).hexdigest() + frames.append({'file': name, 'sha256': digest}) + manifest = { + 'schema': 1, + 'group': os.path.basename(directory), + 'frame_count': len(frames), + 'frames': frames, + } + manifest_path = os.path.join(directory, 'frames.json') + if os.path.isfile(manifest_path): + with open(manifest_path, 'r') as handle: + existing = json.load(handle) + if existing != manifest: + raise AssertionError( + 'frame manifest disagrees with capture: %s' % + manifest_path) + else: + with open(manifest_path, 'w') as handle: + json.dump(manifest, handle, sort_keys=True, indent=2) + handle.write('\n') + sequence_count += 1 + except (IOError, OSError, ValueError, AssertionError) as exc: + print('FATAL: OLED sequence manifest failure: %s' % exc, + file=sys.stderr) + session.exitstatus = 1 + return + + print("[SCREENSHOT] Session complete: %d PNGs in %d manifested sequences" % + (count, sequence_count), file=sys.stderr) diff --git a/tests/emulator_endpoints.py b/tests/emulator_endpoints.py new file mode 100644 index 00000000..c9b25cd5 --- /dev/null +++ b/tests/emulator_endpoints.py @@ -0,0 +1,23 @@ +"""Exact loopback UDP endpoints leased by test-owned emulator processes.""" + +from contextlib import contextmanager + +_owned = set() + + +def is_owned_endpoint(endpoint): + return endpoint in _owned + + +@contextmanager +def owned_emulator_pair(port): + if not isinstance(port, int) or isinstance(port, bool) or not 0 < port < 65535: + raise ValueError("emulator port must leave room for its debug port") + endpoints = {("127.0.0.1", port), ("127.0.0.1", port + 1)} + if endpoints & _owned: + raise RuntimeError("emulator endpoints already leased") + _owned.update(endpoints) + try: + yield + finally: + _owned.difference_update(endpoints) diff --git a/tests/fixtures/erc7730-thorchain-router-v3.json b/tests/fixtures/erc7730-thorchain-router-v3.json new file mode 100644 index 00000000..9445fe27 --- /dev/null +++ b/tests/fixtures/erc7730-thorchain-router-v3.json @@ -0,0 +1,62 @@ +{ + "source": "keepkey-sdk/packages/ts-keepkey-sdk/__tests__/sign-tx-eth-thorchain.js", + "description": "THORChain ETH to BCH swap", + "chainId": 1, + "to": "0x3624525075b88B24ecc29CE226b0CEc1fFcB6976", + "value": "0x5af3107a4000", + "signature": "deposit(address vault,address asset,uint256 amount,string memo)", + "data": "0x1fece7b4000000000000000000000000aff6edbf71badb2bc504c499ac8f344a5cd86008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000343d3a4243482e4243483a717a78703078633676736a3861706739796d346e346a6c3435707978746b70736875767239736d6a7033000000000000000000000000", + "expected": { + "selector": "1fece7b4", + "vault": "0xaff6edbf71badb2bc504c499ac8f344a5cd86008", + "asset": "0x0000000000000000000000000000000000000000", + "amount": "100000000000000", + "memo": "=:BCH.BCH:qzxp0xc6vsj8apg9ym4n4jl45pyxtkpshuvr9smjp3" + }, + "descriptor": { + "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json", + "context": { + "$id": "THORChain Router v3.0.1", + "contract": { + "deployments": [ + { + "chainId": 1, + "address": "0x3624525075b88B24ecc29CE226b0CEc1fFcB6976" + } + ] + } + }, + "metadata": { + "owner": "THORChain", + "contractName": "THORChain Router v3.0.1" + }, + "display": { + "formats": { + "deposit(address vault,address asset,uint256 amount,string memo)": { + "$id": "deposit", + "intent": "Swap via THORChain", + "fields": [ + { + "path": "vault", + "label": "Inbound vault", + "format": "addressName", + "visible": "always" + }, + { + "path": "amount", + "label": "Amount to send", + "format": "amount", + "visible": "always" + }, + { + "path": "memo", + "label": "Swap memo", + "format": "raw", + "visible": "always" + } + ] + } + } + } + } +} diff --git a/tests/oled_text.py b/tests/oled_text.py new file mode 100644 index 00000000..b67d0b7f --- /dev/null +++ b/tests/oled_text.py @@ -0,0 +1,233 @@ +"""Find text on a DebugLink OLED frame. + +DebugLinkState.layout is the display framebuffer -- 256x64, one bit per pixel, +each byte eight vertical pixels with the least significant bit on top -- and +there is no text channel. So a test that must know WHAT a screen says renders +the expected string with the firmware's own glyphs and looks for exactly those +pixels: every ink pixel of every glyph lit, every other pixel of its cell dark. + +The glyph tables below are the title and body fonts of keepkey-firmware +lib/board/font.c (printable ASCII). Regenerate them after a font change with + + python oled_text.py path/to/keepkey-firmware/lib/board/font.c + +A body is found the way confirm() draws it: broken into lines as +draw_string_walk() in lib/board/draw.c breaks them (a 44-character Solana +address always wraps), each line whole -- nothing drawn just before or after +it -- and the lines left-aligned on consecutive rows of ONE screen. A body +that pages is not found; assert each page's part instead. +""" + +from __future__ import print_function + +import re +import sys + +GLYPH_HEIGHT = 10 +BODY_WIDTH = 225 # layout.h BODY_WIDTH, the wrap width of confirm() bodies +BODY_LINE_PITCH = GLYPH_HEIGHT + 4 # font height + BODY_FONT_LINE_PADDING + + +def _font(table): + """'w:rows' per printable character from 0x20, rows as fixed-width hex + with bit i = column i.""" + glyphs = {} + for i, entry in enumerate(table.split()): + width, rows = entry.split(':') + n = len(rows) // GLYPH_HEIGHT + glyphs[chr(0x20 + i)] = (int(width), tuple( + int(rows[r * n:(r + 1) * n], 16) for r in range(GLYPH_HEIGHT))) + assert len(glyphs) == 95 + return glyphs + + +# Generated from keepkey-firmware lib/board/font.c by this module's __main__. +TITLE_FONT = _font(""" +5:000000000000000000000000000000 3:000003003003003003000003000000 5:00000f00f000000000000000000000 8:00003607f03603607f036000000000 +7:00c03e00f00f01e03c03c01f00c000 9:0000c606f03601806c0f6063000000 8:00000e01b01b00e07b03307e000000 3:000003003000000000000000000000 +4:006003003003003003003003006000 4:003006006006006006006006003000 7:00c03f01e03f00c000000000000000 7:00000000c00c03f00c00c000000000 +4:000000000000000000007007006003 7:00000000000003f000000000000000 4:000000000000000000007007000000 9:0000c006003001800c006003000000 +7:00001e03303b03f03703301e000000 4:000007006006006006006006000000 7:00001f03003001e00300303f000000 7:00001f03003001e03003001f000000 +7:00001801c01e01b03f018018000000 7:00003f00300301f03003001f000000 7:00001e00300301f03303301e000000 7:00003f03001801800c00c006000000 +7:00001e03303301e03303301e000000 7:00001e03303303e03003001e000000 4:000000000007007000007007000000 4:000000000007007000007007006003 +6:00001800c00600300600c018000000 7:00000000003f00003f000000000000 6:00000300600c01800c006003000000 7:00001e03303001800c00000c000000 +9:07c0c61bb1e31fb1ef0fb00607c000 7:00001e03303303f033033033000000 7:00001f03303301f03303301f000000 7:00001e03300300300303301e000000 +7:00001f03303303303303301f000000 7:00003f00300301f00300303f000000 7:00003f00300301f003003003000000 7:00001e03300303b03303303e000000 +7:00003303303303f033033033000000 5:00000f00600600600600600f000000 7:00003003003003003003301e000000 7:00003301b00f00700f01b033000000 +7:00000300300300300300303f000000 9:0000c30e70ff0db0c30c30c3000000 7:00003303303703f03b033033000000 7:00001e03303303303303301e000000 +7:00001f03303303301f003003000000 7:00001e03303303303303301e030000 7:00001f03303303301f01b033000000 7:00001e03300301e03003301e000000 +7:00003f00c00c00c00c00c00c000000 7:00003303303303303303301e000000 7:00003303303303301e01e00c000000 9:0000db0db0db0db0db0db07e000000 +7:00003303301e00c01e033033000000 7:00003303303301e00c00c00c000000 7:00003f03001800c00600303f000000 5:00000f00300300300300300f000000 +9:00000300600c0180300600c0000000 5:00000f00c00c00c00c00c00f000000 5:00000600f000000000000000000000 7:00000000000000000000003f000000 +4:000003006000000000000000000000 7:00000000001e03003e03303e000000 7:00000300301f03303303301f000000 7:00000000003e00300300303e000000 +7:00003003003e03303303303e000000 7:00000000001e03303f00303e000000 6:00001c00601f006006006006000000 7:00000000003e03303303303e03001e +7:00000300301f033033033033000000 3:000003000003003003003003000000 4:000006000006006006006006006003 6:00000300301b00f00700f01b000000 +3:000003003003003003003003000000 9:00000000007f0db0db0db0db000000 7:00000000001f033033033033000000 7:00000000001e03303303301e000000 +7:00000000001f03303303301f003003 7:00000000003e03303303303e030030 6:00000000001f007003003003000000 7:00000000003e00301e03001f000000 +6:00000600601f00600600601c000000 7:00000000003303303303303e000000 7:00000000003303301e01e00c000000 9:0000000000db0db0db0db07e000000 +7:00000000003301e00c01e033000000 7:00000000003303303303303e03001e 7:00000000003f01800c00603f000000 6:00001c00600600300600601c000000 +3:000003003003003003003003000000 6:00000700c00c01800c00c007000000 7:00003e01f000000000000000000000 +""") + +BODY_FONT = _font(""" +4:00000000000000000000 2:00010101010100010000 4:00050500000000000000 7:00123f12123f12000000 +6:041e05050e14140f0400 8:00422512082452210000 7:000609090629112e0000 2:00010100000000000000 +3:02010101010101010200 3:01020202020202020100 6:04150e15040000000000 6:000004041f0404000000 +3:00000000000003030201 6:000000001f0000000000 3:00000000000003030000 8:00402010080402010000 +6:000e11191513110e0000 3:00030202020202020000 6:000f10100e01011f0000 6:000f10100e10100f0000 +6:00080c0a091f08080000 6:001f01010f10100f0000 6:000e01010f11110e0000 6:001f1008080404020000 +6:000e11110e11110e0000 6:000e11111e10100e0000 3:00000003030003030000 3:00000003030003030201 +5:00080402010204080000 6:0000001f001f00000000 5:00010204080402010000 6:000e1110080400040000 +8:3c4299a1b9a579023c00 6:000e11111f1111110000 6:000f11110f11110f0000 6:000e11010101110e0000 +6:000f11111111110f0000 6:001f01010f01011f0000 6:001f01010f0101010000 6:000e11011d11111e0000 +6:001111111f1111110000 4:00070202020202070000 6:001010101010110e0000 6:00110905030509110000 +6:000101010101011f0000 8:00416355494141410000 6:00111113151911110000 6:000e11111111110e0000 +6:000f1111110f01010000 6:000e11111111110e1000 6:000f1111110f09110000 6:000e11010e10110e0000 +6:001f0404040404040000 6:001111111111110e0000 6:00111111110a0a040000 8:00494949494949360000 +6:0011110a040a11110000 6:001111110a0404040000 6:001f10080402011f0000 4:00070101010101070000 +8:00010204081020400000 4:00070404040404070000 4:00020500000000000000 6:000000000000001f0000 +3:00010200000000000000 6:0000000e101e111e0000 6:0001010f1111110f0000 6:0000001e0101011e0000 +6:0010101e1111111e0000 6:0000000e111f011e0000 5:000c020f020202020000 6:0000001e1111111e100e +6:0001010f111111110000 2:00010001010101010000 3:00020002020202020201 5:00010109050305090000 +2:00010101010101010000 8:0000003f494949490000 6:0000000f111111110000 6:0000000e1111110e0000 +6:0000000f1111110f0101 6:0000001e1111111e1010 5:0000000d030101010000 6:0000001e010e100f0000 +5:0002020f0202020c0000 6:000000111111111e0000 6:00000011110a0a040000 8:00000049494949360000 +6:000000110a040a110000 6:000000111111111e100e 6:0000001f0804021f0000 5:000c02020102020c0000 +2:00010101010101010000 5:00030404080404030000 7:00404020201214080000 +""") + + +def wrap(text, font=BODY_FONT, width=BODY_WIDTH): + """The lines draw_string_walk() breaks `text` into.""" + lines, line, x = [], '', 0 + for i, c in enumerate(text): + if c == '\n': + lines.append(line) + line, x = '', 0 + continue + word = font[c][0] + if c == ' ': + for n in text[i + 1:]: + if n in ' \n': + break + word += font[n][0] + if x + word > width: + lines.append(line) + line, x = '', 0 + if x == 0 and c == ' ': + continue + line += c + x += font[c][0] + lines.append(line) + return lines + + +def _rows(layout): + rows = [0] * 64 + for x in range(256): + for band in range(8): + byte = layout[x + band * 256] + if not isinstance(byte, int): + byte = ord(byte) + for bit in range(8): + if byte >> bit & 1: + rows[band * 8 + bit] |= 1 << x + return rows + + +def _render(line, font): + rows, x = [0] * GLYPH_HEIGHT, 0 + for c in line: + width, glyph = font[c] + for r in range(GLYPH_HEIGHT): + rows[r] |= glyph[r] << x + x += width + return x, rows + + +def _at(rows, want, width, x, y, whole): + """`want` drawn at (x, y); if `whole`, with nothing lit within a glyph's + width on either side of it (a longer line is not this line).""" + mask = (1 << width) - 1 + if any((rows[y + r] >> x) & mask != want[r] for r in range(GLYPH_HEIGHT)): + return False + if not whole: + return True + before = min(x, 9) + edges = ((1 << before) - 1) << (x - before) | 0x1ff << (x + width) + return not any(rows[y + r] & edges for r in range(GLYPH_HEIGHT)) + + +def find_line(layout, line, font=BODY_FONT): + """(x, y) of the topmost rendering of `line` (a prefix of a longer line + counts), or None.""" + width, want = _render(line, font) + rows = _rows(layout) + for y in range(64 - GLYPH_HEIGHT + 1): + for x in range(256 - width + 1): + if _at(rows, want, width, x, y, False): + return x, y + return None + + +def shows(layout, text, font=BODY_FONT, width=BODY_WIDTH): + """Whether this screen shows `text` as confirm() draws a body.""" + lines = [_render(line, font) for line in wrap(text, font, width)] + rows = _rows(layout) + height = (len(lines) - 1) * BODY_LINE_PITCH + GLYPH_HEIGHT + for y in range(64 - height + 1): + for x in range(256 - lines[0][0] + 1): + if all(_at(rows, want, w, x, y + i * BODY_LINE_PITCH, True) + for i, (w, want) in enumerate(lines)): + return True + return False + + +def find_text(screens, text, font=BODY_FONT, width=BODY_WIDTH, start=0): + """Index of the first screen from `start` that shows `text`, or None.""" + for i in range(start, len(screens)): + if shows(screens[i], text, font, width): + return i + return None + + +def _generate(font_c): + src = open(font_c).read() + data = {m.group(1): [int(v, 16) for v in + re.findall(r'0x([0-9a-fA-F]{2})', m.group(2))] + for m in re.finditer( + r'static const uint8_t (image_data_\w+)\[[^\]]*\]\s*=\s*' + r'\{([^}]*)\}', src)} + images = {m.group(1): (m.group(2), int(m.group(3)), int(m.group(4))) + for m in re.finditer( + r'static const CharacterImage (\w+)\s*=\s*\{\s*(\w+),\s*' + r'(\d+),\s*(\d+)\s*\}', src)} + out = {} + for name in ('title_font', 'body_font'): + array = re.search(r'static const Character %s_array\[\]\s*=\s*\{(.*?)' + r'\n\};' % name, src, re.S).group(1) + glyphs = {} + for code, image in re.findall(r'\{\s*(0x[0-9a-fA-F]+)\s*,\s*&(\w+)\s*\}', + array): + if not 0x20 <= int(code, 16) <= 0x7e: + continue + pixels, width, height = images[image] + assert height == GLYPH_HEIGHT, image + ink = data[pixels] + assert len(ink) == width * height, image + glyphs[int(code, 16)] = (width, [ + sum(1 << x for x in range(width) if ink[y * width + x] == 0) + for y in range(height)]) + assert sorted(glyphs) == list(range(0x20, 0x7f)), name + digits = (max(w for w, _ in glyphs.values()) + 3) // 4 + entries = ['%d:%s' % (w, ''.join('%0*x' % (digits, r) for r in rows)) + for w, rows in (glyphs[c] for c in range(0x20, 0x7f))] + out[name] = '\n'.join(' '.join(entries[i:i + 4]) + for i in range(0, len(entries), 4)) + return out + + +if __name__ == '__main__': + tables = _generate(sys.argv[1]) + print('TITLE_FONT = _font("""\n%s\n""")\n' % tables['title_font']) + print('BODY_FONT = _font("""\n%s\n""")' % tables['body_font']) diff --git a/tests/test_erc7730_catalog.py b/tests/test_erc7730_catalog.py index 5f58e808..9501fa17 100644 --- a/tests/test_erc7730_catalog.py +++ b/tests/test_erc7730_catalog.py @@ -1,15 +1,27 @@ import hashlib import pytest +from ecdsa import SECP256k1, SigningKey, util from keepkeylib import erc7730 from keepkeylib import messages_ethereum_pb2 as ethereum +from keepkeylib.signed_metadata import TEST_PRIVATE_KEY ADDRESS = bytes.fromhex("11" * 20) SELECTOR = bytes.fromhex("1fece7b4") +def minimal_program(): + program = bytearray(179) + program[:4] = b"C773" + program[4:8] = bytes((1, 2, 0, 1)) + program[10:18] = (1).to_bytes(8, "big") + program[18:38] = ADDRESS + program[38:42] = SELECTOR + return bytes(program) + + def definition(payload=b"signed-envelope"): return erc7730.Definition(payload, ethereum.ERC7730_CALLDATA, 1, ADDRESS, SELECTOR) @@ -72,3 +84,48 @@ def test_preload_streams_and_checks_every_acknowledgement(): client = PreloadClient(item.envelope) erc7730.preload(client, item) assert client.offset == len(item.envelope) + + +def test_signed_catalog_envelope_commits_program_proof_and_certificate(): + program = minimal_program() + proof = (bytes.fromhex("22" * 32), bytes.fromhex("33" * 32)) + certificate = bytes(range(139)) + envelope = erc7730.sign_envelope( + program, certificate, TEST_PRIVATE_KEY, proof) + assert envelope == erc7730.sign_envelope( + program, certificate, TEST_PRIVATE_KEY, proof) + assert envelope[:10] == b"K773\x01\x01" + len(program).to_bytes(4, "big") + cursor = 10 + len(program) + assert envelope[cursor] == len(proof) + cursor += 1 + assert envelope[cursor:cursor + 64] == b"".join(proof) + cursor += 64 + assert envelope[cursor:cursor + 2] == (139).to_bytes(2, "big") + cursor += 2 + assert envelope[cursor:cursor + 139] == certificate + cursor += 139 + signature = envelope[cursor:cursor + 64] + assert envelope[cursor + 64] in (0, 1) + assert len(envelope) == cursor + 65 + + digest = hashlib.sha256( + erc7730.CATALOG_DOMAIN + erc7730.catalog_root(program, proof)).digest() + public_key = SigningKey.from_string( + TEST_PRIVATE_KEY, curve=SECP256k1).get_verifying_key() + assert public_key.verify_digest(signature, digest, + sigdecode=util.sigdecode_string) + assert erc7730.catalog_root(program, proof) != erc7730.catalog_root(program) + + +@pytest.mark.parametrize("program,certificate,private_key,proof", [ + (b"short", bytes(139), TEST_PRIVATE_KEY, ()), + (minimal_program(), bytes(138), TEST_PRIVATE_KEY, ()), + (minimal_program(), bytes(139), bytes(31), ()), + (minimal_program(), bytes(139), TEST_PRIVATE_KEY, (bytes(31),)), + (minimal_program(), bytes(139), TEST_PRIVATE_KEY, + tuple(bytes(32) for _ in range(17))), +]) +def test_signed_catalog_envelope_rejects_invalid_bounds( + program, certificate, private_key, proof): + with pytest.raises(ValueError): + erc7730.sign_envelope(program, certificate, private_key, proof) diff --git a/tests/test_erc7730_compiler.py b/tests/test_erc7730_compiler.py new file mode 100644 index 00000000..576d8284 --- /dev/null +++ b/tests/test_erc7730_compiler.py @@ -0,0 +1,504 @@ +from __future__ import absolute_import + +import hashlib +import json +import os +import subprocess +import struct +import tempfile + +import pytest + +from keepkeylib.erc7730_compiler import ( + HEADER_SIZE, compile_calldata, compile_eip712, eip712_encode_type, + load_descriptor, parse_function_signature, +) +from keepkeylib.signed_metadata import keccak256 + + +def _sections(program): + count = program[178] + offset = HEADER_SIZE + result = {} + for _ in range(count): + kind = program[offset] + length = struct.unpack(">I", program[offset + 1:offset + 5])[0] + result[kind] = program[offset + 5:offset + 5 + length] + offset += 5 + length + assert offset == len(program) + return result + + +def _rlp_item(data, offset=0): + prefix = data[offset] + if prefix <= 0x7f: + return bytes([prefix]), offset + 1 + if prefix <= 0xb7: + length = prefix - 0x80 + start = offset + 1 + return data[start:start + length], start + length + if prefix <= 0xbf: + width = prefix - 0xb7 + length = int.from_bytes(data[offset + 1:offset + 1 + width], "big") + start = offset + 1 + width + return data[start:start + length], start + length + if prefix <= 0xf7: + length = prefix - 0xc0 + start = offset + 1 + else: + width = prefix - 0xf7 + length = int.from_bytes(data[offset + 1:offset + 1 + width], "big") + start = offset + 1 + width + end = start + length + values = [] + while start < end: + value, start = _rlp_item(data, start) + values.append(value) + assert start == end + return values, end + + +def _ethereum_transaction(raw_hex): + raw = bytes.fromhex(raw_hex[2:]) + typed = raw[0] in (1, 2, 3, 4) + transaction, end = _rlp_item(raw, 1 if typed else 0) + assert end == len(raw) + if typed and raw[0] == 2: + return int.from_bytes(transaction[0], "big"), transaction[5], transaction[7] + if typed: + raise ValueError("unsupported typed fixture") + return None, transaction[3], transaction[5] + + +def test_parses_recursive_tuple_and_array_signature(): + name, root = parse_function_signature( + "route((address token,uint256 amount)[] legs,address recipient)") + assert name == "route" + assert root.children[0].name == "legs" + assert root.children[0].kind == 9 + assert root.children[0].children[0].children[1].name == "amount" + + +def test_compiles_deterministic_canonical_calldata_program(): + descriptor = { + "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json", + "context": {"contract": {"deployments": [ + {"chainId": 1, + "address": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45"} + ]}}, + "display": {"formats": { + "swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to)": { + "intent": "Swap", + "fields": [ + {"path": "amountIn", "label": "Amount to Send", + "format": "tokenAmount", + "params": {"tokenPath": "path.[0]"}}, + {"path": "amountOutMin", "label": "Minimum to Receive", + "format": "tokenAmount", + "params": {"tokenPath": "path.[-1]"}}, + {"path": "to", "label": "Recipient", + "format": "addressName"}, + ], + } + }}, + } + kwargs = dict( + signature="swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to)", + chain_id=1, + address="0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", + token_records=[ + (1, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "WETH", 18), + ], + network_records=[(1, "Ethereum", "ETH", 18)], + ) + first = compile_calldata(descriptor, **kwargs) + second = compile_calldata(descriptor, **kwargs) + assert first == second + assert first[:4] == b"C773" + assert first[4:8] == bytes([1, 2, 0, 1]) + assert first[10:18] == struct.pack(">Q", 1) + assert first[18:38] == bytes.fromhex( + "68b3465833fb72a70ecdf485e0e4c7bd8665fc45") + # Registry fixture has the four-argument router variant; the selector is + # computed from its canonical ABI rather than copied from descriptor data. + assert first[38:42].hex() == "472b43f3" + assert first[42:70] == bytes(28) + sections = _sections(first) + assert set(sections) == {1, 2, 3, 6, 7, 8, 9} + assert hashlib.sha256(first).digest() == hashlib.sha256(second).digest() + assert len(first) < 16384 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as compiled: + compiled.write(first) + compiled.flush() + subprocess.check_call([validator, compiled.name]) + + +def test_compiles_official_uniswap_tuple_fixture_through_firmware(): + registry = os.environ.get("ERC7730_REGISTRY") + if not registry: + pytest.skip("official ERC-7730 registry not configured") + path = os.path.join( + registry, "registry", "uniswap", "calldata-UniswapV3Router02.json") + with open(path, "r") as source: + descriptor = json.load(source) + tests_path = os.path.join( + registry, "registry", "uniswap", "testsv2", + "calldata-UniswapV3Router02.tests.json") + with open(tests_path, "r") as source: + fixtures = json.load(source)["tests"] + signature = ( + "exactInputSingle((address tokenIn, address tokenOut, uint24 fee, " + "address recipient, uint256 amountIn, uint256 amountOutMinimum, " + "uint160 sqrtPriceLimitX96) params)") + compiled = compile_calldata( + descriptor, signature, 1, + "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45", + token_records=[ + (1, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "WETH", 18), + (1, "0xdac17f958d2ee523a2206206994597c13d831ec7", "USDT", 6), + ], + network_records=[(1, "Ethereum", "ETH", 18)], + ) + assert compiled[38:42].hex() == "04e45aaf" + chain_id, target, calldata = _ethereum_transaction(fixtures[1]["rawTx"]) + assert chain_id == 1 + assert target.hex() == "68b3465833fb72a70ecdf485e0e4c7bd8665fc45" + assert calldata[:4] == compiled[38:42] + assert fixtures[1]["txHash"] == ( + "0xb25281abb3e6bbfe18c746187522c2e915aa02fdb8175082005340e00c1f0b30") + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_and_checks_exact_keepkey_sdk_thorchain_swap(): + fixture_path = os.path.join( + os.path.dirname(__file__), "fixtures", "erc7730-thorchain-router-v3.json") + with open(fixture_path, "r") as source: + fixture = json.load(source) + calldata = bytes.fromhex(fixture["data"][2:]) + expected = fixture["expected"] + assert calldata[:4].hex() == expected["selector"] + assert ("0x" + calldata[16:36].hex()) == expected["vault"] + assert ("0x" + calldata[48:68].hex()) == expected["asset"] + assert str(int.from_bytes(calldata[68:100], "big")) == expected["amount"] + dynamic_offset = int.from_bytes(calldata[100:132], "big") + memo_length = int.from_bytes( + calldata[4 + dynamic_offset:4 + dynamic_offset + 32], "big") + memo = calldata[4 + dynamic_offset + 32: + 4 + dynamic_offset + 32 + memo_length].decode("utf-8") + assert memo == expected["memo"] + assert int(fixture["value"], 16) == int(expected["amount"]) + + compiled = compile_calldata( + fixture["descriptor"], fixture["signature"], fixture["chainId"], + fixture["to"], network_records=[(1, "Ethereum", "ETH", 18)]) + assert compiled[38:42].hex() == expected["selector"] + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_array_iteration_separator_and_optional_visibility(): + descriptor = { + "display": {"formats": { + "batch((address recipient,uint256 amount)[] items)": { + "intent": "Batch transfer", + "fields": [{ + "path": "items.[].recipient", + "label": "Recipient", + "format": "addressName", + "separator": "Next recipient", + "visible": "optional", + }], + } + }} + } + compiled = compile_calldata( + descriptor, + "batch((address recipient,uint256 amount)[] items)", 1, + "0x1111111111111111111111111111111111111111") + sections = _sections(compiled) + assert 5 in sections + display = sections[7] + count = int.from_bytes(display[:2], "big") + opcodes = [display[2 + i * 8] for i in range(count)] + assert opcodes == [1, 7, 4, 8, 10] + begin = display[10:18] + end = display[26:34] + assert int.from_bytes(begin[6:8], "big") == 3 + assert int.from_bytes(end[2:4], "big") == 1 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_recursive_array_iteration_frames(): + descriptor = {"display": {"formats": { + "matrix(uint256[][] values)": { + "intent": "Review matrix", + "fields": [{"path": "values.[].[]", "label": "Value", + "format": "raw", "separator": "Next row"}], + } + }}} + compiled = compile_calldata( + descriptor, "matrix(uint256[][] values)", 1, + "0x1111111111111111111111111111111111111111") + display = _sections(compiled)[7] + count = int.from_bytes(display[:2], "big") + instructions = [display[2 + i * 8:10 + i * 8] for i in range(count)] + assert [item[0] for item in instructions] == [1, 7, 7, 4, 8, 8, 10] + assert int.from_bytes(instructions[1][6:8], "big") == 5 + assert int.from_bytes(instructions[2][6:8], "big") == 4 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_token_amount_without_token_uses_firmware_raw_fallback(): + descriptor = {"display": {"formats": { + "quote(uint256 amount)": { + "intent": "Review quote", + "fields": [{"path": "amount", "label": "Unknown token amount", + "format": "tokenAmount"}], + } + }}} + compiled = compile_calldata( + descriptor, "quote(uint256 amount)", 1, + "0x1111111111111111111111111111111111111111") + formatter = _sections(compiled)[6] + assert formatter[2:5] == bytes([3, 0, 1]) + assert formatter[5:9] == bytes([1, 1, 0, 0]) + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_typed_if_not_in_and_must_match_conditions(): + descriptor = {"display": {"formats": { + "guard(uint256 mode,address recipient)": { + "intent": "Guarded call", + "fields": [ + {"path": "mode", "label": "Mode", "format": "raw", + "visible": {"ifNotIn": [0, 255]}}, + {"path": "recipient", "label": "Bound recipient", + "format": "addressName", + "visible": {"mustMatch": [ + "0x2222222222222222222222222222222222222222"]}}, + ], + } + }}} + compiled = compile_calldata( + descriptor, "guard(uint256 mode,address recipient)", 1, + "0x1111111111111111111111111111111111111111") + sections = _sections(compiled) + conditions = sections[5] + assert int.from_bytes(conditions[:2], "big") == 2 + assert conditions[2] == 7 + assert conditions[10] == 8 + literals = sections[4] + assert int.from_bytes(literals[:2], "big") == 5 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_interpolated_intent_and_metadata_enum(): + descriptor = { + "metadata": {"enums": {"side": {"false": "Buy", "true": "Sell"}}}, + "display": {"formats": { + "swap(bool selling,uint256 amount)": { + "intent": "Swap", + "interpolatedIntent": "Swap {amount} as {selling}", + "fields": [ + {"path": "selling", "label": "Side", "format": "enum", + "params": {"$ref": "$.metadata.enums.side"}, + "visible": "always"}, + {"path": "amount", "label": "Amount", "format": "raw", + "visible": "always"}, + ], + } + }} + } + compiled = compile_calldata( + descriptor, "swap(bool selling,uint256 amount)", 1, + "0x1111111111111111111111111111111111111111") + sections = _sections(compiled) + display = sections[7] + count = int.from_bytes(display[:2], "big") + opcodes = [display[2 + i * 8] for i in range(count)] + assert opcodes == [1, 2, 3, 2, 3, 4, 4, 10] + formatters = sections[6] + assert int.from_bytes(formatters[:2], "big") == 2 + assert formatters[2] == 8 + literals = sections[4] + assert int.from_bytes(literals[:2], "big") == 3 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_compiles_nested_field_group_with_balanced_links(): + descriptor = {"display": {"formats": { + "act((address owner,uint256 amount) details)": { + "intent": "Grouped action", + "fields": [{ + "path": "details", "label": "Details", "fields": [ + {"path": "owner", "label": "Owner", + "format": "addressName"}, + {"path": "amount", "label": "Amount", "format": "raw"}, + ], + }], + } + }}} + compiled = compile_calldata( + descriptor, "act((address owner,uint256 amount) details)", 1, + "0x1111111111111111111111111111111111111111") + display = _sections(compiled)[7] + count = int.from_bytes(display[:2], "big") + instructions = [display[2 + i * 8:10 + i * 8] for i in range(count)] + assert [item[0] for item in instructions] == [1, 5, 4, 4, 6, 10] + assert int.from_bytes(instructions[1][6:8], "big") == 4 + assert int.from_bytes(instructions[4][2:4], "big") == 1 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_loads_bounded_includes_and_compiles_array_backed_group(tmp_path): + shared = { + "display": {"definitions": { + "recipient": {"label": "Recipient", "format": "addressName"} + }} + } + descriptor = { + "includes": "shared.json", + "display": {"formats": { + "batch((address to,uint256 amount)[] items)": { + "intent": "Batch", + "fields": [{"path": "items.[]", "label": "Item", + "fields": [ + {"path": "to", + "$ref": "$.display.definitions.recipient"}, + {"path": "amount", "label": "Amount", + "format": "raw"}, + ]}], + } + }} + } + (tmp_path / "shared.json").write_text(json.dumps(shared)) + path = tmp_path / "descriptor.json" + path.write_text(json.dumps(descriptor)) + loaded = load_descriptor(str(path), str(tmp_path)) + compiled = compile_calldata( + loaded, "batch((address to,uint256 amount)[] items)", 1, + "0x1111111111111111111111111111111111111111") + display = _sections(compiled)[7] + count = int.from_bytes(display[:2], "big") + opcodes = [display[2 + i * 8] for i in range(count)] + assert opcodes == [1, 7, 5, 4, 4, 6, 8, 10] + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) + + +def test_official_registry_all_calldata_formats_reach_firmware(): + registry = os.environ.get("ERC7730_REGISTRY") + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if not registry or not validator: + pytest.skip("official registry and firmware validator are required") + import glob + failures = [] + checked = 0 + for path in glob.glob(os.path.join( + registry, "registry", "**", "calldata-*.json"), recursive=True): + descriptor = load_descriptor(path, registry) + deployments = descriptor.get("context", {}).get( + "contract", {}).get("deployments", []) + if not deployments: + continue + deployment = deployments[0] + if (not isinstance(deployment.get("chainId"), int) or + not isinstance(deployment.get("address"), str)): + continue + for signature in descriptor.get("display", {}).get("formats", {}): + checked += 1 + try: + program = compile_calldata( + descriptor, signature, deployment["chainId"], + deployment["address"]) + with tempfile.NamedTemporaryFile() as output: + output.write(program) + output.flush() + subprocess.check_call( + [validator, output.name], stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + except Exception as exc: + failures.append("%s :: %s :: %s" % ( + os.path.basename(path), signature, exc)) + assert checked == 1450 + assert failures == [] + + +def test_compiles_official_uniswap_eip712_fixture_through_firmware(): + registry = os.environ.get("ERC7730_REGISTRY") + if not registry: + pytest.skip("official ERC-7730 registry not configured") + with open(os.path.join(registry, "registry", "uniswap", + "eip712-uniswap-permit2.json"), "r") as source: + descriptor = json.load(source) + with open(os.path.join(registry, "registry", "uniswap", "testsv2", + "eip712-uniswap-permit2.tests.json"), "r") as source: + fixture = json.load(source)["tests"][0]["data"] + encoded = eip712_encode_type(fixture["primaryType"], fixture["types"]) + assert encoded == ( + "PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)" + "PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)") + compiled = compile_eip712( + descriptor, fixture, + token_records=[ + (1, "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "USDC", 6) + ], network_records=[(1, "Ethereum", "ETH", 18)]) + assert compiled[7] == 2 + assert compiled[10:18] == (1).to_bytes(8, "big") + assert compiled[18:38].hex() == "000000000022d473030f116ddee9f6b43ac78ba3" + assert compiled[38:70] == keccak256(encoded.encode("ascii")) + sections = _sections(compiled) + binding = sections[8] + # deployment + name/chain/contract domain facts + token + network + assert int.from_bytes(binding[:2], "big") == 6 + validator = os.environ.get("ERC7730_FIRMWARE_VALIDATOR") + if validator: + with tempfile.NamedTemporaryFile() as output: + output.write(compiled) + output.flush() + subprocess.check_call([validator, output.name]) diff --git a/tests/test_msg_authenticator_boundaries.py b/tests/test_msg_authenticator_boundaries.py new file mode 100644 index 00000000..8f0e8417 --- /dev/null +++ b/tests/test_msg_authenticator_boundaries.py @@ -0,0 +1,76 @@ +# This file is part of the TREZOR project. +# +# Copyright (C) 2026 KeepKey +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +from __future__ import print_function + +import unittest + +import common +import keepkeylib.messages_pb2 as proto +import keepkeylib.types_pb2 as proto_types + + +class TestAuthenticatorBoundaries(common.KeepKeyTest): + # 7.15 enforces the RFC-recommended 128-bit minimum for TOTP secrets. + ADD_ACCOUNT = ('\x15initializeAuth:example:alice:' + 'JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP') + GET_ACCOUNT = '\x17getAccount:0' + WIPE_ACCOUNTS = '\x19wipeAuthdata:' + + def _auth_ping(self, message): + return self.client.call(proto.Ping(message=message)) + + def _reject_passphrase_and_assert_no_account(self): + response = self.client.call_raw(proto.Ping(message=self.GET_ACCOUNT)) + self.assertIsInstance(response, proto.PassphraseRequest) + + response = self.client.call_raw(proto.Cancel()) + self.assertIsInstance(response, proto.Failure) + self.assertEqual(response.code, proto_types.Failure_ActionCancelled) + self.assertNotIn('example:alice', response.message) + + def test_authorization_loss_drops_cache_and_requires_reauthorization(self): + self.client.load_device_by_mnemonic( + mnemonic=self.mnemonic12, + pin='', + passphrase_protection=True, + label='test', + language='english') + self.client.set_passphrase('authenticator-wallet') + + # Authenticator storage is encrypted independently from the wallet. + # Initialize its fingerprint for this passphrase before adding data. + response = self._auth_ping(self.WIPE_ACCOUNTS) + self.assertIsInstance(response, proto.Success) + response = self._auth_ping(self.ADD_ACCOUNT) + self.assertIsInstance(response, proto.Success) + self.assertEqual(self._auth_ping(self.GET_ACCOUNT).message, + 'example:alice') + + authorization_losses = ( + ('ClearSession/lock', lambda: self.client.call(proto.ClearSession())), + ('Initialize', lambda: self.client.call(proto.Initialize())), + ) + + for name, revoke in authorization_losses: + response = revoke() + self.assertIsInstance(response, (proto.Success, proto.Features, + proto.Failure), name) + self._reject_passphrase_and_assert_no_account() + + # The rejected operation must not have consumed or changed the + # persistent account. A fresh authorization reloads it from the + # encrypted storage rather than a stale plaintext cache. + response = self._auth_ping(self.GET_ACCOUNT) + self.assertIsInstance(response, proto.Success, name) + self.assertEqual(response.message, 'example:alice') + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_bip85.py b/tests/test_msg_bip85.py index 4a0b2b89..1020d280 100644 --- a/tests/test_msg_bip85.py +++ b/tests/test_msg_bip85.py @@ -20,6 +20,7 @@ class TestMsgBip85(common.KeepKeyTest): def setUp(self): super().setUp() self.requires_firmware("7.15.0") + self.requires_fullFeature() def test_bip85_12word_flow(self): """12-word derivation: verify device goes through display flow and returns Success.""" diff --git a/tests/test_msg_bitcoin_only_variant.py b/tests/test_msg_bitcoin_only_variant.py index bb00b6d4..b89dee64 100644 --- a/tests/test_msg_bitcoin_only_variant.py +++ b/tests/test_msg_bitcoin_only_variant.py @@ -107,7 +107,11 @@ class TestBitcoinOnlyVariant(common.KeepKeyTest): def setUp(self): super(TestBitcoinOnlyVariant, self).setUp() - self.requires_firmware("7.15.0") + # The Bitcoin-only product shipped on the 7.14.3 release fork before + # 7.15. The variant check below keeps these product assertions away + # from regular 7.14.x images, while this exact floor prevents the + # stripped 7.14.3 emulator from silently skipping its entire suite. + self.requires_firmware("7.14.3") # This whole file describes the BITCOIN-ONLY product. Several tests # assert screen sequences that differ on the multi-chain build -- the # OP_RETURN one decodes a THORChain memo there and draws more screens -- diff --git a/tests/test_msg_changepin.py b/tests/test_msg_changepin.py index ad414a2a..3eaec4d1 100644 --- a/tests/test_msg_changepin.py +++ b/tests/test_msg_changepin.py @@ -39,6 +39,7 @@ def test_set_pin(self): # Let's set new PIN ret = self.client.call_raw(proto.ChangePin()) self.assertIsInstance(ret, proto.ButtonRequest) + self.client._capture_oled() # Press button self.client.debug.press_yes() @@ -46,11 +47,13 @@ def test_set_pin(self): # Send the PIN for first time self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for second time self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) @@ -87,6 +90,7 @@ def test_change_pin(self): # Let's change PIN ret = self.client.call_raw(proto.ChangePin()) self.assertIsInstance(ret, proto.ButtonRequest) + self.client._capture_oled() # Press button self.client.debug.press_yes() @@ -94,16 +98,19 @@ def test_change_pin(self): # Send current PIN self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.read_pin_encoded() ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send new PIN for first time self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) # Send the PIN for second time self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) @@ -137,6 +144,7 @@ def test_remove_pin(self): # Let's remove PIN ret = self.client.call_raw(proto.ChangePin(remove=True)) self.assertIsInstance(ret, proto.ButtonRequest) + self.client._capture_oled() # Press button self.client.debug.press_yes() @@ -144,6 +152,7 @@ def test_remove_pin(self): # Send current PIN self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) pin_encoded = self.client.debug.read_pin_encoded() ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) diff --git a/tests/test_msg_confirm_data_disclosure.py b/tests/test_msg_confirm_data_disclosure.py new file mode 100644 index 00000000..d15377aa --- /dev/null +++ b/tests/test_msg_confirm_data_disclosure.py @@ -0,0 +1,181 @@ +# This file is part of the KeepKey project. +# +# Copyright (C) 2026 KeepKey +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. + +"""Every byte passed through firmware ``confirm_data`` must reach the OLED.""" + +from __future__ import print_function + +import binascii + +import common + +from keepkeylib import messages_eos_pb2 as eos_messages +from keepkeylib import types_pb2 as types +from keepkeylib.tools import parse_path +from test_msg_display_disclosure import ScreenRecorder + + +PREV_HASH = binascii.unhexlify( + "d5f65ee80147b4bcc70b75e4bbf2d738" + "2021b871bd8867ef8fa525ef50864882" +) +EOS_PATH = parse_path("m/44'/194'/0'/0/0") + + +class TestConfirmDataDisclosure(common.KeepKeyTest): + def setUp(self): + super(TestConfirmDataDisclosure, self).setUp() + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + + def _capture_op_return(self, payload, group): + tx_input = types.TxInputType( + address_n=[0], prev_hash=PREV_HASH, prev_index=0 + ) + payment = types.TxOutputType( + address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", + amount=380000, + script_type=types.PAYTOADDRESS, + ) + data_output = types.TxOutputType( + op_return_data=payload, + amount=0, + script_type=types.PAYTOOPRETURN, + ) + recorder = ScreenRecorder( + self.client, answer=True, screenshot_group=group + ) + with recorder: + _, serialized = self.client.sign_tx( + "Bitcoin", [tx_input], [payment, data_output] + ) + return recorder.fingerprint, serialized + + def _capture_eos_memo(self, memo, group): + transaction = { + "chain_id": ( + "cf057bbfb72640471fd910bcb67639c22" + "df9f92470936cddc1ade0e2f2e7dc4f" + ), + "transaction": { + "expiration": "2018-07-14T07:43:28", + "ref_block_num": 6439, + "ref_block_prefix": 2995713264, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio.token", + "name": "transfer", + "authorization": [{ + "actor": "miniminimini", + "permission": "active", + }], + "data": { + "from": "miniminimini", + "to": "maximaximaxi", + "quantity": "1.0000 EOS", + "memo": memo, + }, + }], + "transaction_extensions": [], + }, + } + recorder = ScreenRecorder( + self.client, answer=True, screenshot_group=group + ) + with recorder: + signed = self.client.eos_sign_tx(EOS_PATH, transaction) + signature = ( + bytes(signed.signature_r), + bytes(signed.signature_s), + signed.signature_v, + ) + return recorder.fingerprint, signature + + def test_binary_op_return_tail_changes_oled_review(self): + """A byte after the old 50-byte binary preview must be displayed.""" + common_prefix = b"\x80" + b"A" * 79 + payload_a = common_prefix + b"X" * 16 + payload_b = common_prefix + b"Y" + b"X" * 15 + + screens_a, signed_a = self._capture_op_return(payload_a, "opreturn-a") + # Run each member of the A/B pair from the same clean device state. + # Multi-page review ends with a held confirmation, so merely opening a + # new protocol session can retain a trailing emulator button event. + self.client.wipe_device() + self.setup_mnemonic_nopin_nopassphrase() + screens_b, signed_b = self._capture_op_return(payload_b, "opreturn-b") + + self.assertNotEqual(signed_a, signed_b) + self.assertGreater(len(screens_a), 1) + self.assertGreater(len(screens_b), 1) + self.assertNotEqual( + screens_a, screens_b, + "different signed OP_RETURN tails produced identical OLED review", + ) + + def test_non_ascii_eos_memo_tail_changes_oled_review(self): + """A UTF-8 memo byte after the old 50-byte preview must be displayed.""" + common_prefix = "\u00e9" + "A" * 79 + memo_a = common_prefix + "X" * 16 + memo_b = common_prefix + "Y" + "X" * 15 + + screens_a, signed_a = self._capture_eos_memo(memo_a, "eos-a") + self.client.wipe_device() + self.setup_mnemonic_nopin_nopassphrase() + screens_b, signed_b = self._capture_eos_memo(memo_b, "eos-b") + + self.assertNotEqual(signed_a, signed_b) + self.assertGreater(len(screens_a), 1) + self.assertGreater(len(screens_b), 1) + self.assertNotEqual( + screens_a, screens_b, + "different signed EOS memo tails produced identical OLED review", + ) + + def test_unknown_omni_property_changes_oled_review(self): + """Unsupported Omni assets must disclose bytes, not a shared ticker.""" + header = b"omni\x00\x00\x00\x00" + (999999).to_bytes(4, "big") + payload_a = header + (1).to_bytes(8, "big") + payload_b = header + (2).to_bytes(8, "big") + + screens_a, signed_a = self._capture_op_return(payload_a, "omni-prop-a") + self.client.wipe_device() + self.setup_mnemonic_nopin_nopassphrase() + screens_b, signed_b = self._capture_op_return(payload_b, "omni-prop-b") + + self.assertNotEqual(signed_a, signed_b) + self.assertNotEqual( + screens_a, screens_b, + "different unsupported Omni assets produced identical OLED review", + ) + + def test_unknown_omni_type_changes_oled_review(self): + """Unsupported Omni operations must disclose the complete payload.""" + header = b"omni\x00\x00\x00\x01" + (31).to_bytes(4, "big") + payload_a = header + (1).to_bytes(8, "big") + payload_b = header + (2).to_bytes(8, "big") + + screens_a, signed_a = self._capture_op_return(payload_a, "omni-type-a") + self.client.wipe_device() + self.setup_mnemonic_nopin_nopassphrase() + screens_b, signed_b = self._capture_op_return(payload_b, "omni-type-b") + + self.assertNotEqual(signed_a, signed_b) + self.assertNotEqual( + screens_a, screens_b, + "different unsupported Omni operations produced identical review", + ) + + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/tests/test_msg_display_disclosure.py b/tests/test_msg_display_disclosure.py index 4a37c417..c7493380 100644 --- a/tests/test_msg_display_disclosure.py +++ b/tests/test_msg_display_disclosure.py @@ -52,6 +52,9 @@ from __future__ import print_function +import os +import hashlib +import json import unittest import common @@ -69,38 +72,47 @@ class ScreenRecorder(object): displayed; reading it afterwards would only ever see the home screen. """ - def __init__(self, client, answer=True): + def __init__(self, client, answer=True, screenshot_group=None): self.client = client self.answer = answer + self.screenshot_group = screenshot_group self.screens = [] self._original = None + self._original_screenshot_dir = None + self._original_screenshot_id = None + self._group_dir = None def __enter__(self): client = self.client recorder = self self._original = client.callback_ButtonRequest + if self.screenshot_group and getattr(client, 'screenshot_dir', None): + self._original_screenshot_dir = client.screenshot_dir + self._original_screenshot_id = client.screenshot_id + client.screenshot_dir = os.path.join( + client.screenshot_dir, self.screenshot_group + ) + os.makedirs(client.screenshot_dir, exist_ok=True) + self._group_dir = client.screenshot_dir + client.screenshot_id = 0 def recording_callback(msg): - try: - layout = client.debug.read_layout() - if layout: - recorder.screens.append(bytes(layout)) - except Exception: - # A capture failure must not mask the behaviour under test; - # the assertions below check what was captured. - pass - try: - # Also emit the frame as a PNG through the normal capture path. - # This class answers ButtonRequests itself, which bypasses the - # client's own capture hook -- so under KEEPKEY_SCREENSHOT=1 - # these tests were selected by the screenshot filter, passed, - # and produced NO images. The screens this suite exists to - # police were the ones nobody could look at. - if getattr(client, 'screenshot_dir', None): - client._capture_oled() - except Exception: - pass + # ButtonRequest is written immediately before the firmware draws + # a paged confirmation's next OLED frame. Reading once here can + # therefore retain the previous page twice and omit the new one. + # Use the same settled framebuffer primitive as the production + # screenshot callback, then bind assertions and PNG output to + # that one byte sequence. + layout = client._read_oled_after_settle() + if not layout: + raise AssertionError("ButtonRequest produced no OLED layout") + recorder.screens.append(bytes(layout)) + # Use the same framebuffer for the assertion and PNG. A second + # DebugLink read can race the button transition and make the PDF + # evidence disagree with the bytes the test actually compared. + if getattr(client, 'screenshot_dir', None): + client._capture_oled(layout=layout) if recorder.answer: client.debug.press_yes() else: @@ -112,6 +124,38 @@ def recording_callback(msg): def __exit__(self, exc_type, exc_value, tb): self.client.callback_ButtonRequest = self._original + try: + if exc_type is None and self._group_dir is not None: + expected = ["btn%05d.png" % i + for i in range(len(self.screens))] + actual = sorted( + name for name in os.listdir(self._group_dir) + if name != "frames.json" + ) + if actual != expected: + raise AssertionError( + "OLED group %s is incomplete: expected=%r actual=%r" % + (self.screenshot_group, expected, actual)) + frames = [] + for name in expected: + path = os.path.join(self._group_dir, name) + with open(path, "rb") as handle: + digest = hashlib.sha256(handle.read()).hexdigest() + frames.append({"file": name, "sha256": digest}) + manifest = { + "schema": 1, + "group": self.screenshot_group, + "frame_count": len(frames), + "frames": frames, + } + manifest_path = os.path.join(self._group_dir, "frames.json") + with open(manifest_path, "w") as handle: + json.dump(manifest, handle, sort_keys=True, indent=2) + handle.write("\n") + finally: + if self._original_screenshot_dir is not None: + self.client.screenshot_dir = self._original_screenshot_dir + self.client.screenshot_id = self._original_screenshot_id return False @property diff --git a/tests/test_msg_eos_signtx.py b/tests/test_msg_eos_signtx.py index 033d61d2..b009ab23 100644 --- a/tests/test_msg_eos_signtx.py +++ b/tests/test_msg_eos_signtx.py @@ -560,6 +560,18 @@ def test_updateauth(self): self.assertEqual(binascii.hexlify(res.hash), "0282c00575f451a47e99902ab2a51243499ea004df309148d1f2e23c007520b7") + # Fork #568/#563: eos_hashAuthorization() used to emit accounts_count + # wait entries instead of waits_count. This SLIP-48 vector has one + # delegated account and zero waits, so older firmware hashes a phantom + # 6-byte zero wait that was neither present nor confirmed on-device + # (the known-bad digest fb936ef1...). The fix is on the 7.14.3, 7.15 + # and 7.16 release heads. 5938294e... is checked against two + # independent EOSIO ABI serializers and against mainnet updateauth + # transactions of the same shape. + if not self.firmware_at_least("7.14.3"): + self.skipTest("Firmware before 7.14.3 hashes a phantom updateauth " + "wait (fork #568/#563)") + res = self.client.eos_sign_tx_raw( proto.EosSignTx( address_n=parse_path("m/48'/4'/0'/0'/0'"), @@ -568,17 +580,7 @@ def test_updateauth(self): num_actions=1), [self.action_updateauth(True)]) - # Firmware #568 (7.16.0) fixed eos_hashAuthorization() to serialize - # waits_count entries, not accounts_count entries. This SLIP-48 vector - # has one delegated account and zero waits; the old golden committed a - # phantom zero wait that was neither present nor confirmed on-device. - version = (self.client.features.major_version, - self.client.features.minor_version, - self.client.features.patch_version) - expected = ("5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1" - if version >= (7, 16, 0) - else "fb936ef1be4bda680d93bd10b6d062357d8dd7272038a706dc0d61a91f39c5ee") - self.assertEqual(binascii.hexlify(res.hash), expected) + self.assertEqual(binascii.hexlify(res.hash), "5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1") def test_deleteauth(self): self.requires_fullFeature() diff --git a/tests/test_msg_ethereum_clear_signing.py b/tests/test_msg_ethereum_clear_signing.py index 20242357..72cd80db 100644 --- a/tests/test_msg_ethereum_clear_signing.py +++ b/tests/test_msg_ethereum_clear_signing.py @@ -1018,8 +1018,8 @@ def test_binding_happy_path_signs_and_recovers(self): def _clearsign_flow(self, flow, chain_id=1): """Run one catalog flow END-TO-END with AdvancedMode ON: real tx, per-tx-bound metadata, who/what/why annotation plus the ordinary raw - review (auto-acked), sign, and assert the signature recovers to the - device signer over this exact digest.""" + review (auto-acked), then either sign and recover the exact digest or + assert the release policy's explicit fail-closed rejection.""" n = parse_path(DEVICE_PATH) tx_hash = flow_tx_hash(flow, chain_id) resp = self.client.ethereum_send_tx_metadata( @@ -1027,6 +1027,17 @@ def _clearsign_flow(self, flow, chain_id=1): metadata_version=1, key_id=TEST_KEY_ID) self.assertEqual(resp.classification, CLASSIFICATION_VERIFIED) + if flow['key'] == 'erc20-approve-unlimited': + with self.assertRaises(CallException) as ctx: + self.client.ethereum_sign_tx( + n=n, nonce=FLOW_NONCE, gas_price=FLOW_GAS_PRICE, + gas_limit=FLOW_GAS_LIMIT, to=flow['to'], + value=flow['value'], data=flow['data'], + chain_id=chain_id) + self.assertIn('Unlimited ERC20 approval is disabled', + str(ctx.exception)) + return + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=n, nonce=FLOW_NONCE, gas_price=FLOW_GAS_PRICE, gas_limit=FLOW_GAS_LIMIT, to=flow['to'], value=flow['value'], @@ -1089,11 +1100,8 @@ def test_replay_rejected_when_digest_differs(self): def test_advanced_mode_gate(self): """AdvancedMode OFF + unknown contract + no metadata → hard reject; ON → raw-data confirm path signs; recognized ERC-20 transfer unaffected.""" - # RC18 predates the rule that loading a runtime signer itself requires - # AdvancedMode. The first released firmware line carrying that complete - # gate is 7.16; the older blind-transaction gate remains covered by - # test_msg_ethereum_signtx on RC18. - self.requires_firmware("7.16.0") + # Canonical 7.15 requires AdvancedMode before runtime signer loading. + self.requires_firmware("7.15.0") n = parse_path(DEVICE_PATH) data = aave_supply_calldata(1000000000000000000) diff --git a/tests/test_msg_ethereum_clearsign_additive.py b/tests/test_msg_ethereum_clearsign_additive.py index 49b43d1b..8ea7194a 100644 --- a/tests/test_msg_ethereum_clearsign_additive.py +++ b/tests/test_msg_ethereum_clearsign_additive.py @@ -87,10 +87,9 @@ # METADATA_MAX_KEYS in include/keepkey/firmware/signed_metadata.h. METADATA_MAX_KEYS = 4 -# RC18 verifies runtime metadata, but the successful-decode path did not yet -# guarantee that the ordinary raw review survived byte-for-byte. That security -# invariant landed after RC18 and first ships on the 7.16 line. -ADDITIVE_REVIEW_FIRMWARE = "7.16.0" +# The canonical 7.15 product requires additive runtime provider review. +# Do not inherit the earlier RC18 candidate's capability assumptions. +ADDITIVE_REVIEW_FIRMWARE = "7.15.0" # The Aave V3 supply() transaction every additive test signs. Real ABI # calldata (selector + 4 x 32-byte words), so the metadata below binds a diff --git a/tests/test_msg_ethereum_data_disclosure.py b/tests/test_msg_ethereum_data_disclosure.py new file mode 100644 index 00000000..5cf4e824 --- /dev/null +++ b/tests/test_msg_ethereum_data_disclosure.py @@ -0,0 +1,78 @@ +# This file is part of the KeepKey project. + +"""Arbitrary Ethereum calldata approval must bind to every streamed byte.""" + +from __future__ import print_function + +import binascii +import unittest + +import common + +from keepkeylib.tools import parse_path +from test_msg_display_disclosure import ScreenRecorder + + +class TestEthereumDataDisclosure(common.KeepKeyTest): + PATH = parse_path("m/44'/60'/0'/0/0") + CONTRACT = binascii.unhexlify( + "4c82d1fbfe28c977cbb58d8c7ff8fcf9f70a2cca" + ) + + def setUp(self): + super(TestEthereumDataDisclosure, self).setUp() + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_allallall() + self.client.apply_policy("AdvancedMode", 1) + + def _capture(self, data, group): + recorder = ScreenRecorder( + self.client, answer=True, screenshot_group=group + ) + with recorder: + signature = self.client.ethereum_sign_tx( + n=self.PATH, + nonce=0, + gas_price=20000000000, + gas_limit=200000, + to=self.CONTRACT, + value=0, + chain_id=1, + data=data, + ) + return recorder.fingerprint, signature + + def _assert_pair(self, data_a, data_b, group_a, group_b): + screens_a, signature_a = self._capture(data_a, group_a) + self.client.wipe_device() + self.setup_mnemonic_allallall() + self.client.apply_policy("AdvancedMode", 1) + screens_b, signature_b = self._capture(data_b, group_b) + self.assertNotEqual(signature_a, signature_b) + self.assertGreater(len(screens_a), 1) + self.assertGreater(len(screens_b), 1) + self.assertNotEqual( + screens_a, screens_b, + "different calldata produced identical complete OLED approval", + ) + + def test_initial_chunk_tail_changes_data_hash_screen(self): + prefix = b"\xde\xad\xbe\xef" + b"A" * 60 + self._assert_pair( + prefix + b"X" * 32, + prefix + b"Y" + b"X" * 31, + "initial-a", "initial-b", + ) + + def test_streamed_tail_changes_data_hash_screen(self): + prefix = b"\xde\xad\xbe\xef" + b"A" * 1296 + self._assert_pair( + prefix + b"X" * 32, + prefix + b"Y" + b"X" * 31, + "streamed-a", "streamed-b", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_msg_ethereum_erc20_approve.py b/tests/test_msg_ethereum_erc20_approve.py index 8a851ac3..ed9cab03 100644 --- a/tests/test_msg_ethereum_erc20_approve.py +++ b/tests/test_msg_ethereum_erc20_approve.py @@ -71,6 +71,21 @@ def test_approve_cvc_all(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + if self.firmware_at_least("7.14.2"): + with self.assertRaises(CallException): + self.client.ethereum_sign_tx( + n=[2147483692,2147483708,2147483648,0,0], + nonce=1, + gas_price=20, + gas_limit=20, + value=0, + to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), + address_type=0, + chain_id=1, + data=binascii.unhexlify('095ea7b3' + '0000000000000000000000001d8ce9022f6284c3a5c317f8f34620107214e545' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + ) + return + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], nonce=1, diff --git a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py index 6e7824e5..a4508be4 100644 --- a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py +++ b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py @@ -27,36 +27,47 @@ class TestMsgEthereumUniswaptxERC20(common.KeepKeyTest): + def setUp(self): + super(TestMsgEthereumUniswaptxERC20, self).setUp() + # Canonical 7.15 routes unknown token contracts through explicitly + # authorized raw review. Exercise that path instead of an emulator skip. + self.requires_firmware("7.15.0") + def test_sign_uni_approve_liquidity_ETH(self): self.requires_fullFeature() self.requires_firmware("7.1.0") self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy("AdvancedMode", 1) - # Approval tx for the ETH/FOX pool - sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( - n=[2147483692,2147483708,2147483648,0,0], - nonce=0xf, - gas_price=0x2980872680, - gas_limit=0xbd0e, - value=0x0, - to=binascii.unhexlify('470e8de2ebaef52014a47cb5e6af86884947f08c'), # fox pool - address_type=0, - chain_id=1, - # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and - # keccak signatures (4 bytes) - data=binascii.unhexlify('095ea7b3' + # approve - '0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' + # uniswap v2: router 2 contract address - 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') # approve amount + # Unlimited approval is deliberately disabled on canonical 7.15. + # This legacy vector must be refused, not skipped or signed. + with self.assertRaises(CallException) as caught: + self.client.ethereum_sign_tx( + n=[2147483692,2147483708,2147483648,0,0], + nonce=0xf, + gas_price=0x2980872680, + gas_limit=0xbd0e, + value=0x0, + to=binascii.unhexlify('470e8de2ebaef52014a47cb5e6af86884947f08c'), # fox pool + address_type=0, + chain_id=1, + # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and + # keccak signatures (4 bytes) + data=binascii.unhexlify('095ea7b3' + # approve + '0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' + # uniswap v2: router 2 contract address + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') # approve amount + + ) + self.assertEqual(caught.exception.args[0], + proto_types.Failure_ActionCancelled) + self.assertIn("Unlimited ERC20 approval is disabled", + str(caught.exception)) - ) - self.assertEqual(sig_v, 38) - self.assertEqual(binascii.hexlify(sig_r), '7f7a5ce501371a01ead394d2186385742d5fbdc3d85da98249d2a05043ac6d5a') - self.assertEqual(binascii.hexlify(sig_s), '329954b284ed1df9a6242820e793b9719c0c6c21cae5f90190ce61c7f73c731e') - def test_sign_uni_add_liquidity_ETH(self): self.requires_fullFeature() self.requires_firmware("7.1.0") self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy("AdvancedMode", 1) # Add liquidity to ETH/FOX pool sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( @@ -68,7 +79,7 @@ def test_sign_uni_add_liquidity_ETH(self): to=binascii.unhexlify('7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), # UNISWAP router address_type=0, chain_id=1, - # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and + # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and # keccak signatures (4 bytes) data=binascii.unhexlify('f305d719' + # addLiquidityETH '000000000000000000000000c770eefad204b5180df6a14ee197d99d808ee52d' + # FOX token @@ -77,17 +88,16 @@ def test_sign_uni_add_liquidity_ETH(self): '0000000000000000000000000000000000000000000000000000fb98b65aba40' + # min amount of eth token '0000000000000000000000003f2329C9ADFbcCd9A84f52c906E936A42dA18CB8' + # eth address (self) '00000000000000000000000000000000000000000000000000000178a9380e5f') # deadline - ) + ) self.assertEqual(sig_v, 37) - self.assertEqual(binascii.hexlify(sig_r), '8547542bc74c0dcc6ca8b02a79e0dccd336856d8c48376289a2a697d864a5892') - self.assertEqual(binascii.hexlify(sig_s), '0a8eec6856aef8caa234240b06862976f8e238e8b24f5c989279507dd7e51ccd') + self.assertEqual(binascii.hexlify(sig_r).decode("ascii"), '8547542bc74c0dcc6ca8b02a79e0dccd336856d8c48376289a2a697d864a5892') + self.assertEqual(binascii.hexlify(sig_s).decode("ascii"), '0a8eec6856aef8caa234240b06862976f8e238e8b24f5c989279507dd7e51ccd') def test_sign_uni_remove_liquidity_ETH(self): self.requires_fullFeature() - # Sending the withdrawn assets to a third-party recipient was refused - # by RC18. The reviewed external-recipient flow lands on the 7.16 line. - self.requires_firmware("7.16.0") + self.requires_firmware("7.1.0") self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy("AdvancedMode", 1) # remove liquidity from the ETH/FOX pool sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( @@ -99,7 +109,7 @@ def test_sign_uni_remove_liquidity_ETH(self): to=binascii.unhexlify('7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), # UNISWAP router address_type=0, chain_id=1, - # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and + # The data below is generally broken into 32-byte chunks except for the function selector (4 bytes_ and # keccak signatures (4 bytes) data=binascii.unhexlify('02751cec' + # addLiquidityETH '000000000000000000000000c770eefad204b5180df6a14ee197d99d808ee52d' + # FOX token @@ -108,10 +118,10 @@ def test_sign_uni_remove_liquidity_ETH(self): '0000000000000000000000000000000000000000000000000000fb04c77f3e94' + # min amount of eth token '0000000000000000000000005028d647b74f12903e6d5f3969f8f624e6a9a93d' + # to address (not self) '00000000000000000000000000000000000000000000000000000178b2062f3d') # deadline - ) + ) self.assertEqual(sig_v, 37) - self.assertEqual(binascii.hexlify(sig_r), '7143f0d8e5505a8cfb1df55e9c5d7433eba33a61959137c08cc5c088ec12ab5d') - self.assertEqual(binascii.hexlify(sig_s), '20b456d6c13295f5abb6109d7ade2c5d5fc395963b1e45d92e6dc8c33749c517') + self.assertEqual(binascii.hexlify(sig_r).decode("ascii"), '7143f0d8e5505a8cfb1df55e9c5d7433eba33a61959137c08cc5c088ec12ab5d') + self.assertEqual(binascii.hexlify(sig_s).decode("ascii"), '20b456d6c13295f5abb6109d7ade2c5d5fc395963b1e45d92e6dc8c33749c517') if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_ethereum_getaddress.py b/tests/test_msg_ethereum_getaddress.py index da66e406..501ad8d6 100644 --- a/tests/test_msg_ethereum_getaddress.py +++ b/tests/test_msg_ethereum_getaddress.py @@ -34,5 +34,13 @@ def test_ethereum_getaddress(self): self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([-9, 0])), 'f68804ac9eca9483ab4241d3e4751590d2c05102') self.assertEqual(binascii.hexlify(self.client.ethereum_get_address([0, 9999999])), '7a6366ecfcaf0d5dcc1539c171696c6cdd1eb8ed') + def test_ethereum_show_address(self): + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + # The legacy display response is empty after the ButtonAck; address + # correctness is covered above. This case exists to retain the actual + # operation-specific OLED sequence for visual review. + self.client.ethereum_get_address([], show_display=True) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_ethereum_makerdao.py b/tests/test_msg_ethereum_makerdao.py index b79066d6..f7da7135 100644 --- a/tests/test_msg_ethereum_makerdao.py +++ b/tests/test_msg_ethereum_makerdao.py @@ -30,6 +30,8 @@ class TestMsgEthereumtxMakerDAO(common.KeepKeyTest): def test_generate(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + # MakerDAO calldata now follows the generic blind-signing path. + self.client.apply_policy("AdvancedMode", 1) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], @@ -50,6 +52,8 @@ def test_generate(self): def test_deposit(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + # MakerDAO calldata now follows the generic blind-signing path. + self.client.apply_policy("AdvancedMode", 1) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], @@ -71,6 +75,8 @@ def test_deposit(self): def test_close(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + # MakerDAO calldata now follows the generic blind-signing path. + self.client.apply_policy("AdvancedMode", 1) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], @@ -92,6 +98,8 @@ def test_close(self): def test_free(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + # MakerDAO calldata now follows the generic blind-signing path. + self.client.apply_policy("AdvancedMode", 1) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], @@ -111,4 +119,3 @@ def test_free(self): if __name__ == '__main__': unittest.main() - diff --git a/tests/test_msg_ethereum_signtx.py b/tests/test_msg_ethereum_signtx.py index 16747941..379395cb 100644 --- a/tests/test_msg_ethereum_signtx.py +++ b/tests/test_msg_ethereum_signtx.py @@ -21,15 +21,154 @@ import unittest import common import binascii +import hashlib import keepkeylib.messages_pb2 as proto import keepkeylib.messages_ethereum_pb2 as eth_proto import keepkeylib.types_pb2 as proto_types from keepkeylib.client import CallException from keepkeylib.tools import int_to_big_endian +from test_msg_display_disclosure import ScreenRecorder class TestMsgEthereumSigntx(common.KeepKeyTest): + def test_ethereum_native_pseudo_address_is_unknown_off_mainnet(self): + """0xeeee..eeee must render as unknown for chain-257 token calls.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy("AdvancedMode", 1) + common.reset_screenshot_capture(self.client) + + recipient = self.client.ethereum_get_address([0, 0]) + pseudo_address = b"\xee" * 20 + if self.firmware_at_least("7.15.0"): + expected_frames = { + "transfer": ( + "843693d0c5f8f87986a1769c6e5192a6746cbfcb24c7c4c37d335b10c1f5b54c"), + } + else: + # 7.14.3 uses the pre-7.15 review layout while proving the same + # off-mainnet unknown-token property. + expected_frames = { + "transfer": ( + "85d9054ee56836c1784c90dd777fc89444bf82b840d0818a59c73aa5b57ee35d"), + "approve": ( + "ab30156ff400957ffa9146ea827318bf878614e6ab4ae7dd731824e285fa5da6"), + } + calls = ( + ( + "transfer", + binascii.unhexlify("a9059cbb" + "00" * 12) + + recipient + int_to_big_endian(1).rjust(32, b"\x00"), + expected_frames["transfer"], + ), + ( + "approve", + binascii.unhexlify("095ea7b3" + "00" * 12) + + recipient + int_to_big_endian(1).rjust(32, b"\x00"), + expected_frames.get("approve"), + ), + ) + + observed_frames = {} + try: + for label, data, expected_frame_sha256 in calls: + with ScreenRecorder( + self.client, + screenshot_group="pseudo-%s" % label) as recorder: + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=60000, + to=pseudo_address, value=0, chain_id=257, data=data, + ) + self.assertGreaterEqual(len(recorder.screens), 2) + observed_frames[label] = hashlib.sha256( + recorder.screens[0]).hexdigest() + if expected_frame_sha256 is not None: + self.assertEqual( + observed_frames[label], expected_frame_sha256) + if self.firmware_at_least("7.15.0"): + self.assertNotEqual( + observed_frames["transfer"], observed_frames["approve"]) + finally: + self.client.apply_policy("AdvancedMode", 0) + common.reset_screenshot_capture(self.client) + + def test_ethereum_erc20_high_chain_id_does_not_alias_mainnet(self): + """Chain 257 must not borrow chain-1 token labels or decimals.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy("AdvancedMode", 1) + + recipient = self.client.ethereum_get_address([0, 0]) + erc20_data = ( + binascii.unhexlify("a9059cbb" + "00" * 12) + + recipient + int_to_big_endian(1).rjust(32, b"\x00") + ) + contract = binascii.unhexlify( + "d0d6d6c5fe4a677d343cc433536bb717bae167dd" + ) + + first_screens = {} + try: + for chain_id in (1, 257): + with ScreenRecorder(self.client) as recorder: + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=60000, + to=contract, value=0, chain_id=chain_id, + data=erc20_data, + ) + self.assertGreaterEqual(len(recorder.screens), 2) + first_screens[chain_id] = recorder.screens[0] + finally: + self.client.apply_policy("AdvancedMode", 0) + + self.assertNotEqual(first_screens[1], first_screens[257]) + + def test_ethereum_unrenderable_amounts_are_rejected(self): + """Neither a native nor ERC-20 amount may reach an approval blank.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + + recipient = binascii.unhexlify( + "1d1c328764a41bda0492b66baa30c4a339ff85ef" + ) + max_uint256 = (1 << 256) - 1 + + with self.client: + self.client.set_expected_responses([ + proto.Failure( + code=proto_types.Failure_SyntaxError, + message="Ethereum amount too large"), + ]) + with self.assertRaises(CallException): + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=21000, + to=recipient, value=max_uint256, chain_id=1, + ) + + # Known mainnet ERC-20 transfer with the same unrenderable amount. + erc20_data = ( + binascii.unhexlify("a9059cbb" + "00" * 12) + + recipient + int_to_big_endian(max_uint256).rjust(32, b"\x00") + ) + with self.client: + self.client.set_expected_responses([ + proto.Failure( + code=proto_types.Failure_SyntaxError, + message="Ethereum amount too large"), + ]) + with self.assertRaises(CallException): + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=60000, + to=binascii.unhexlify( + "d0d6d6c5fe4a677d343cc433536bb717bae167dd" + ), + value=0, chain_id=1, data=erc20_data, + ) + def test_ethereum_signtx_data(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() @@ -99,39 +238,55 @@ def test_ethereum_signtx_data(self): self.client.apply_policy("AdvancedMode", 0) def test_ethereum_blind_sign_blocked(self): - """AdvancedMode OFF + contract data = device refuses to sign (7.15+). + """AdvancedMode OFF + contract data = device refuses to sign (7.14.2+). OLED shows the blind-sign refusal, then Failure. The wire message is 7.14.2's "Arbitrary contract data signing disabled by policy", which replaced alpha's shorter "Blind signing disabled" -- it names WHICH policy refused and what it refused. + The device identifies the transaction destination, displays one + non-approving Blocked notice, then returns the policy failure. The + exact two-ButtonRequest -> Failure sequence proves the host cannot + advance from that notice into a signing approval. """ - self.requires_firmware("7.15.0") + self.requires_firmware("7.14.2") self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 0) - - try: - self.client.ethereum_sign_tx( - n=[0, 0], - nonce=0, - gas_price=20, - gas_limit=20, - to=binascii.unhexlify("1d1c328764a41bda0492b66baa30c4a339ff85ef"), - value=0, - data=b"abcdefghijklmnop" * 16, - chain_id=1, - ) - self.fail("Expected Failure -- blind signing should be blocked") - except CallException as e: - message = str(e) - self.assertTrue( - "Arbitrary contract data signing disabled by policy" in message - or "Blind signing disabled by policy" in message, - "unexpected blind-sign refusal: %s" % message) + common.reset_screenshot_capture(self.client) + + with self.client: + self.client.set_expected_responses([ + proto.ButtonRequest( + code=proto_types.ButtonRequest_ConfirmOutput), + proto.ButtonRequest( + code=proto_types.ButtonRequest_Other), + proto.Failure( + code=proto_types.Failure_ActionCancelled, + message=( + "Arbitrary contract data signing disabled by policy")), + ]) + try: + self.client.ethereum_sign_tx( + n=[0, 0], + nonce=0, + gas_price=20, + gas_limit=20, + to=binascii.unhexlify( + "1d1c328764a41bda0492b66baa30c4a339ff85ef"), + value=0, + data=b"abcdefghijklmnop" * 16, + chain_id=1, + ) + self.fail( + "Expected Failure -- blind signing should be blocked") + except CallException as e: + self.assertIn( + "Arbitrary contract data signing disabled by policy", + str(e)) def test_ethereum_blind_sign_allowed(self): - """AdvancedMode ON + contract data = device shows BLIND SIGNATURE warning (7.15+). + """AdvancedMode ON permits opaque contract-data signing (7.14.2+). OLED shows 'BLIND SIGNATURE' before signing. """ @@ -139,6 +294,7 @@ def test_ethereum_blind_sign_allowed(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 1) + common.reset_screenshot_capture(self.client) sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[0, 0], @@ -289,9 +445,8 @@ def test_ethereum_signtx_omitted_chain_id_rejected(self): sibling tests in this file all now pass chain_id explicitly so they keep exercising their own subject rather than this one. """ - # Explicit zero was already rejected on RC18, but an omitted field was - # not. The absent-field fix landed after RC18 and first ships in 7.16. - self.requires_firmware("7.16.0") + # Canonical 7.15 rejects omitted chain IDs as well as explicit zero. + self.requires_firmware("7.15.0") self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 1) diff --git a/tests/test_msg_ethereum_signtx_xfer.py b/tests/test_msg_ethereum_signtx_xfer.py index 9919ed75..942ec608 100644 --- a/tests/test_msg_ethereum_signtx_xfer.py +++ b/tests/test_msg_ethereum_signtx_xfer.py @@ -21,14 +21,128 @@ import unittest import common import binascii +import hashlib import struct import keepkeylib.messages_pb2 as proto import keepkeylib.types_pb2 as proto_types from keepkeylib.client import CallException from keepkeylib.tools import int_to_big_endian +from test_msg_display_disclosure import ScreenRecorder + class TestMsgEthereumSigntx(common.KeepKeyTest): + def test_native_pseudo_address_transfer_is_unknown_off_mainnet(self): + """TRANSFER must show the exact unknown-token frame on chain 257.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy('ShapeShift', 1) + self.client.apply_policy('AdvancedMode', 1) + common.reset_screenshot_capture(self.client) + + destination_n = [0x8000002c, 0x8000003c, 0x80000001, 0, 0] + recipient = self.client.ethereum_get_address(destination_n) + erc20_data = ( + binascii.unhexlify("a9059cbb" + "00" * 12) + + recipient + int_to_big_endian(1).rjust(32, b"\x00") + ) + + try: + with ScreenRecorder( + self.client, + screenshot_group="pseudo-transfer") as recorder: + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=60000, + value=0, to=b"\xee" * 20, to_n=destination_n, + address_type=proto_types.TRANSFER, + data=erc20_data, chain_id=257, + ) + self.assertGreaterEqual(len(recorder.screens), 2) + # 7.15 explicitly labels the untrusted token value before the raw + # calldata review; pin that first warning frame exactly. + expected_frame = ( + "ec0dc4694860ccc6b3fdbb90efbb27b3b3bd4553d741ef03c89b60cd05097779" + if self.firmware_at_least("7.15.0") else + "b0a3026e7af1778ebd71a968ace25c03945cccf2d8abc951e5dd65abc04e914e" + ) + self.assertEqual( + hashlib.sha256(recorder.screens[0]).hexdigest(), + expected_frame, + ) + finally: + self.client.apply_policy('AdvancedMode', 0) + self.client.apply_policy('ShapeShift', 0) + common.reset_screenshot_capture(self.client) + + def test_transfer_review_uses_signing_chain_asset(self): + """The first transfer approval must change with the signed chain.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy('ShapeShift', 1) + + first_screens = {} + signatures = {} + for chain_id in (1, 56, 137): + with ScreenRecorder(self.client) as recorder: + result = self.client.ethereum_sign_tx( + n=[0, 0], + nonce=0, + gas_price=20000000000, + gas_limit=21000, + value=1500000000000000000, + to_n=[0x8000002c, 0x8000003c, 0x80000001, 0, 0], + address_type=proto_types.TRANSFER, + chain_id=chain_id, + ) + self.assertGreaterEqual(len(recorder.screens), 2) + first_screens[chain_id] = recorder.screens[0] + signatures[chain_id] = result[:3] + + self.assertNotEqual(first_screens[1], first_screens[56]) + self.assertNotEqual(first_screens[56], first_screens[137]) + self.assertNotEqual(signatures[1], signatures[56]) + self.assertNotEqual(signatures[56], signatures[137]) + + self.client.apply_policy('ShapeShift', 0) + + def test_erc20_transfer_high_chain_id_does_not_alias_mainnet(self): + """TRANSFER review must not borrow chain-1 token metadata.""" + self.requires_firmware("7.14.2") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy('ShapeShift', 1) + self.client.apply_policy('AdvancedMode', 1) + + destination_n = [0x8000002c, 0x8000003c, 0x80000001, 0, 0] + recipient = self.client.ethereum_get_address(destination_n) + erc20_data = ( + binascii.unhexlify("a9059cbb" + "00" * 12) + + recipient + int_to_big_endian(1).rjust(32, b"\x00") + ) + contract = binascii.unhexlify( + "d0d6d6c5fe4a677d343cc433536bb717bae167dd" + ) + + first_screens = {} + try: + for chain_id in (1, 257): + with ScreenRecorder(self.client) as recorder: + self.client.ethereum_sign_tx( + n=[0, 0], nonce=0, gas_price=20, gas_limit=60000, + value=0, to=contract, to_n=destination_n, + address_type=proto_types.TRANSFER, + data=erc20_data, chain_id=chain_id, + ) + self.assertGreaterEqual(len(recorder.screens), 2) + first_screens[chain_id] = recorder.screens[0] + finally: + self.client.apply_policy('AdvancedMode', 0) + self.client.apply_policy('ShapeShift', 0) + + self.assertNotEqual(first_screens[1], first_screens[257]) + def test_ethereum_tx_xfer_acc1(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() diff --git a/tests/test_msg_getentropy.py b/tests/test_msg_getentropy.py index f12d4f90..2f4fb948 100644 --- a/tests/test_msg_getentropy.py +++ b/tests/test_msg_getentropy.py @@ -30,10 +30,9 @@ class TestMsgGetentropy(common.KeepKeyTest): - @unittest.skipUnless( - os.getenv('KK_EXPECT_ENTROPY_BUDGET') == '1', - 'requires the RC23 entropy audit budget policy') def test_entropy(self): + if os.getenv("KK_EXPECT_ENTROPY_BUDGET") != "1": + self.requires_firmware("7.15.0") chunk_size = 8192 chunk_count = 8 diff --git a/tests/test_msg_hive.py b/tests/test_msg_hive.py index 78068783..dd175eee 100644 --- a/tests/test_msg_hive.py +++ b/tests/test_msg_hive.py @@ -218,9 +218,12 @@ def _op_delegate_vesting_shares(delegator, delegatee, vesting_shares): def _op_account_update2(account, json_metadata, posting_json_metadata, - authority_present=False): + authority_present=False, memo_key_present=False): + # owner/active/posting/memo_key are all optional<> in op 43 (dhive and + # hive-tx OptionalSerializer): a 0/1 presence byte, then the value. + memo_key = bytes([1, 0x02]) + bytes(32) if memo_key_present else bytes([0]) return (_varint(43) + _string(account) + - bytes([1 if authority_present else 0, 0, 0, 0]) + + bytes([1 if authority_present else 0, 0, 0]) + memo_key + _string(json_metadata) + _string(posting_json_metadata) + _varint(0)) @@ -353,7 +356,11 @@ def test_hive_sign_transfer(self): self.assertEqual((ref_num, ref_prefix, expiration), (12345, 67890, 1700000000)) self.assertEqual(r.string(), b"kktester") # from self.assertEqual(r.string(), b"kkrecipient") # to - self.assertEqual(r.asset(), (1000, 3, "STEEM")) + # The WIRE spelling, per _WIRE_SYMBOL above: hived writes "STEEM" for + # HIVE, and this reads the bytes the device actually signed. Asserting + # the display name here passed only while the firmware serialized a + # symbol the chain does not use. + self.assertEqual(r.asset(), (1000, 3, _WIRE_SYMBOL["HIVE"])) self.assertEqual(r.string(), b"kktest") # memo self.assertEqual(r.varint(), 0) # extensions r.assert_end() @@ -399,7 +406,7 @@ def test_hive_sign_account_create(self): r = _Reader(resp.serialized_tx) ref_num, ref_prefix, expiration = _parse_header(r, HIVE_OP_ACCOUNT_CREATE) self.assertEqual((ref_num, ref_prefix, expiration), (12345, 67890, 1700000000)) - self.assertEqual(r.asset(), (3000, 3, "STEEM")) # fee + self.assertEqual(r.asset(), (3000, 3, _WIRE_SYMBOL["HIVE"])) # fee self.assertEqual(r.string(), b"kksponsor") # creator self.assertEqual(r.string(), b"kktestacct") # new_account_name self.assertEqual(r.authority(), raw[ROLE_OWNER]) @@ -1015,10 +1022,9 @@ def test_hive_sign_ops_comment_options_beneficiary_rules(self): "kkauthor", "my-post", 1000000, 10000, beneficiaries=bens)]) self._assert_ops_fails("beneficiaries", tx) - def test_hive_sign_ops_account_update2_rejects_authority_change(self): - """account_update2 can rotate account keys. Only the profile-metadata - form is in the table — the same device-derived-keys invariant that - keeps ops 9/10 out, applied field-level.""" + def test_hive_sign_ops_account_update2_is_rejected(self): + """account_update2 can rotate account keys. Any authority or memo_key + present is refused, so no key change is summarized as profile-only.""" self.requires_firmware("7.15.0") self.requires_message("HiveSignOperations") self.setup_mnemonic_nopin_nopassphrase() @@ -1029,14 +1035,16 @@ def test_hive_sign_ops_account_update2_rejects_authority_change(self): authority_present=True)]), path=hive_path(ROLE_ACTIVE)) - # json_metadata is an active-key field... - self._ops_signs_with( - _ops_tx([_op_account_update2("kkuser", '{"profile":{}}', "")]), - ROLE_ACTIVE) - # ...while a posting-metadata-only profile edit stays posting tier. - self._ops_signs_with( - _ops_tx([_op_account_update2("kkuser", "", '{"profile":{}}')]), - ROLE_POSTING) + self._assert_ops_fails( + "authority changes", + _ops_tx([_op_account_update2("kkuser", '{"profile":{}}', "", + memo_key_present=True)]), + path=hive_path(ROLE_ACTIVE)) + self._assert_ops_fails( + "authority changes", + _ops_tx([_op_account_update2("kkuser", "", '{"profile":{}}', + memo_key_present=True)]), + path=hive_path(ROLE_POSTING)) def test_hive_sign_ops_truncated_bodies_rejected(self): """The signature covers the whole buffer, so a short read would mean diff --git a/tests/test_msg_osmosis_validation.py b/tests/test_msg_osmosis_validation.py new file mode 100644 index 00000000..2806a716 --- /dev/null +++ b/tests/test_msg_osmosis_validation.py @@ -0,0 +1,80 @@ +import common + +from keepkeylib import messages_osmosis_pb2 as osmosis_proto +from keepkeylib import messages_pb2 as proto +from keepkeylib import types_pb2 as proto_types + + +class TestOsmosisValidation(common.KeepKeyTest): + def setUp(self): + super(TestOsmosisValidation, self).setUp() + self.requires_firmware("7.14.2") + self.requires_message("OsmosisSignTx") + self.setup_mnemonic_nopin_nopassphrase() + + def _start_signing(self): + ret = self.client.call_raw(osmosis_proto.OsmosisSignTx( + address_n=[0x8000002c, 0x80000076, 0x80000000, 0, 0], + account_number=1, + chain_id="osmosis-1", + fee_amount=5000, + gas=300000, + memo="", + sequence=1, + msg_count=1, + )) + self.assertIsInstance(ret, osmosis_proto.OsmosisMsgRequest) + + def _assert_missing_parameter_failure(self, ack): + ret = self.client.call_raw(ack) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_FirmwareError) + self.assertEndsWith(ret.message, "missing required parameters") + + def test_present_but_empty_amount_is_rejected_before_review(self): + # 7.14.3 treats a present-but-empty protobuf string as a missing + # required parameter. Keep that release control explicit even though + # 7.15 adds the stronger, syntax-specific rejection tested below. + if self.firmware_at_least("7.15.0"): + self.skipTest("7.15+ uses the syntax-specific empty amount gate") + self._start_signing() + send = osmosis_proto.OsmosisMsgSend( + to_address="osmo1g9el7lzjwh9yun2c4jjzhy09j98vkhfx8tzcpt", + amount="", + denom="uosmo", + ) + self.assertTrue(send.HasField("amount")) + self._assert_missing_parameter_failure( + osmosis_proto.OsmosisMsgAck(send=send)) + + def test_present_but_empty_amount_is_rejected_as_invalid(self): + # The fail-closed empty-string validator is part of the 7.15 audit + # fixes; 7.14.3 predates that specific Osmosis hardening. + self.requires_firmware("7.15.0") + self._start_signing() + send = osmosis_proto.OsmosisMsgSend( + to_address="osmo1g9el7lzjwh9yun2c4jjzhy09j98vkhfx8tzcpt", + amount="", + denom="uosmo", + ) + self.assertTrue(send.HasField("amount")) + ret = self.client.call_raw(osmosis_proto.OsmosisMsgAck(send=send)) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_SyntaxError) + self.assertEndsWith(ret.message, + "Invalid Osmosis amount or denomination") + + def test_ibc_omitted_amount_and_receiver_are_rejected_before_review(self): + self._start_signing() + transfer = osmosis_proto.OsmosisMsgIBCTransfer( + sender="osmo1g9el7lzjwh9yun2c4jjzhy09j98vkhfx8tzcpt", + source_channel="channel-0", + source_port="transfer", + revision_height="1", + revision_number="1", + denom="uosmo", + ) + self.assertFalse(transfer.HasField("amount")) + self.assertFalse(transfer.HasField("receiver")) + self._assert_missing_parameter_failure( + osmosis_proto.OsmosisMsgAck(ibc_transfer=transfer)) diff --git a/tests/test_msg_ping.py b/tests/test_msg_ping.py index dcff2b85..0943608d 100644 --- a/tests/test_msg_ping.py +++ b/tests/test_msg_ping.py @@ -27,6 +27,25 @@ class TestPing(common.KeepKeyTest): + def test_protected_ping_preserves_message_presence_after_debug_read(self): + self.requires_firmware("7.14.2") + for message in (None, '', 'ping response'): + with self.subTest(message=message): + request = proto.Ping(button_protection=True) + if message is not None: + request.message = message + response = self.client.call_raw(request) + self.assertIsInstance(response, proto.ButtonRequest) + # Read the screen while the normal response is suspended. + self.client.debug.read_layout() + self.client.debug.press_yes() + response = self.client.call_raw(proto.ButtonAck()) + self.assertIsInstance(response, proto.Success) + self.assertEqual(response.HasField('message'), message is not None) + if message is not None: + self.assertEqual(response.message, message) + + def test_ping(self): self.setup_mnemonic_pin_passphrase() self.client.clear_session() @@ -142,15 +161,15 @@ def test_authenticator_passphrase_cancel_is_terminal(self): # local cache. This is the precondition that made the stale-data path # reachable after ClearSession. self.client.ping('\x19wipeAuthdata:') - # Alpha rejects TOTP seeds below the 128-bit minimum. Use a 160-bit - # RFC 4648 Base32 fixture so this test reaches the cancellation path - # it is intended to exercise. - init_auth = ( - '\x15initializeAuth:example.com:alice:' - 'JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP' - ) + init_auth = ('\x15initializeAuth:example.com:alice:' + 'JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP') self.client.ping(init_auth) self.client.clear_session() + # The wipe/add-account confirmations establish the stale-cache + # precondition; they are not evidence for the cancellation boundary. + # Retain only the randomized PIN grid reached by the operation under + # test. Passphrase entry and terminal cancellation are host/wire state. + common.reset_screenshot_capture(self.client) resp = self.client.call_raw(proto.Ping(message='\x17getAccount:0')) self.assertIsInstance(resp, proto.PinMatrixRequest) diff --git a/tests/test_msg_recoverydevice_cipher.py b/tests/test_msg_recoverydevice_cipher.py index d67fd544..ae6d5c72 100644 --- a/tests/test_msg_recoverydevice_cipher.py +++ b/tests/test_msg_recoverydevice_cipher.py @@ -37,11 +37,13 @@ def test_pin_passphrase(self): use_character_cipher=True)) self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for first time pin_encoded = self.client.debug.encode_pin(self.pin6) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for second time pin_encoded = self.client.debug.encode_pin(self.pin6) @@ -49,6 +51,7 @@ def test_pin_passphrase(self): # Reminder UI assert isinstance(ret, proto.ButtonRequest) + self.client._capture_oled_after_animation(0.35, (76, 256, 0, 64)) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) @@ -57,6 +60,8 @@ def test_pin_passphrase(self): for index, word in enumerate(mnemonic_words): for character in word: self.assertIsInstance(ret, proto.CharacterRequest) + self.client._capture_oled_after_animation( + 0.35, (76, 256, 0, 64)) cipher = self.client.debug.read_recovery_cipher() encoded_character = cipher[ord(character) - 97] @@ -107,6 +112,7 @@ def test_nopin_nopassphrase(self): # Reminder UI assert isinstance(ret, proto.ButtonRequest) + self.client._capture_oled_after_animation(0.35, (76, 256, 0, 64)) self.client.debug.press_yes() ret = self.client.call_raw(proto.ButtonAck()) @@ -116,6 +122,8 @@ def test_nopin_nopassphrase(self): for index, word in enumerate(mnemonic_words): for character in word: self.assertIsInstance(ret, proto.CharacterRequest) + self.client._capture_oled_after_animation( + 0.35, (76, 256, 0, 64)) cipher = self.client.debug.read_recovery_cipher() if not captured_cipher: # CharacterRequest is driven manually and never reaches @@ -179,7 +187,7 @@ def test_invalid_bip39_word_rejected(self): With enforce_wordlist=True, completing a word that isn't in the BIP-39 wordlist must return Failure immediately. - Requires firmware 7.15.1+ (per-word validation). + The canonical 7.15 product includes per-word validation. """ self.requires_firmware("7.15.1") ret = self.client.call_raw(proto.RecoveryDevice(word_count=12, @@ -312,7 +320,14 @@ def test_reset_and_recover(self): mnemonic = [] while isinstance(resp, proto.ButtonRequest): - mnemonic.append(self.client.debug.read_reset_word()) + words = self.client.debug.read_reset_word() + # The debug build raises one ButtonRequest per physical + # subpage, and every subpage of a word group reports the same + # reset_word. Whether a group spills onto a second subpage + # depends on glyph widths, so without this the random + # mnemonic made the test flaky ("Invalid mnemonic"). + if not mnemonic or mnemonic[-1] != words: + mnemonic.append(words) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) @@ -437,6 +452,36 @@ def check_n_words(n): for n in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]: check_n_words(n) + def test_unknown_word_count_failure_aborts_recovery(self): + """A terminal Failure must not leave the recovery stream live.""" + self.requires_firmware("7.14.2") + + ret = self.client.call_raw(proto.RecoveryDevice( + passphrase_protection=False, + pin_protection=False, + label='label', + language='english', + enforce_wordlist=True, + use_character_cipher=True, + )) + + self.assertIsInstance(ret, proto.ButtonRequest) + self.client.debug.press_yes() + ret = self.client.call_raw(proto.ButtonAck()) + self.assertIsInstance(ret, proto.CharacterRequest) + + ret = self.client.call_raw(proto.CharacterAck(done=True)) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_SyntaxError) + self.assertEndsWith(ret.message, "12, 18 or 24)") + + # The Failure is a protocol boundary. A stale continuation from the + # old ceremony must be rejected rather than resuming seed entry. + ret = self.client.call_raw(proto.CharacterAck(character='a')) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_UnexpectedMessage) + self.assertEndsWith(ret.message, "Not in Recovery mode") + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_resetdevice.py b/tests/test_msg_resetdevice.py index 5fa212d9..b378f982 100644 --- a/tests/test_msg_resetdevice.py +++ b/tests/test_msg_resetdevice.py @@ -18,15 +18,55 @@ # # The script has been modified for KeepKey Device. -import time import unittest import common import hashlib +import os +import time from keepkeylib import messages_pb2 as proto from keepkeylib import types_pb2 as proto_types from mnemonic import Mnemonic +# Dice derivations, restated here independently of the firmware so the tests +# check the published formula rather than whatever the device happens to do. +# The byte tags match lib/firmware/dice_input.c; the shape mirrors Coldcard's +# so its published verifier applies to ONLY mode unchanged. +DICE_TAG_USER = b'KK\x01D' +DICE_TAG_MIX = b'KK\x01SM' + + +def dice_only_seed(rolls): + """ONLY mode: seed = SHA256(rolls). Nothing else participates.""" + return hashlib.sha256(rolls.encode('ascii')).digest() + + +def dice_mixed_seed(device_entropy, rolls): + """MIXED mode: user = SHA256(tag || rolls); + seed = SHA256(SHA256(tag2 || device_entropy || user)).""" + user = hashlib.sha256(DICE_TAG_USER + rolls.encode('ascii')).digest() + inner = hashlib.sha256(DICE_TAG_MIX + device_entropy + user).digest() + return hashlib.sha256(inner).digest() + + +def bip39_words_to_entropy(words): + """Decode a 24-word BIP-39 sentence to its 32 entropy bytes, checking + the checksum. Written out rather than taken from the mnemonic library so + the words the device showed are decoded by code the device did not + write, and so it does not depend on the library version in the test + image.""" + wordlist = Mnemonic('english').wordlist + words = words.split() + if len(words) != 24: + raise ValueError('expected 24 words, got %d' % len(words)) + bits = ''.join('{:011b}'.format(wordlist.index(w)) for w in words) + entropy = bytes(int(bits[i:i + 8], 2) for i in range(0, 256, 8)) + checksum = '{:08b}'.format(hashlib.sha256(entropy).digest()[0]) + if bits[256:] != checksum: + raise ValueError('BIP-39 checksum mismatch') + return entropy + + def generate_entropy(strength, internal_entropy, external_entropy): ''' strength - length of produced seed. One of 128, 192, 256 @@ -56,13 +96,47 @@ def generate_entropy(strength, internal_entropy, external_entropy): return entropy_stripped class TestDeviceReset(common.KeepKeyTest): - POST_RC18_SETUP_FIRMWARE = "7.16.0" - - def test_reset_device(self): - # No PIN, no passphrase + def _current_layout_for_capture(self): + if os.environ.get('KEEPKEY_SCREENSHOT') != '1': + return None + return self.client.debug.read_layout() + + def _capture_after_stable_transition(self, previous_layout): + """Record the screen belonging to the response we just received. + + ButtonRequest can arrive before the emulator has repainted the OLED. + Capturing immediately therefore retained the preceding screen and + silently omitted the final seed page. Polling DebugLink also advances + the emulator render loop, so require a changed layout to remain stable + for three reads before accepting it as evidence. + """ + if os.environ.get('KEEPKEY_SCREENSHOT') != '1': + return None + + deadline = time.monotonic() + 2.0 + candidate = None + stable_reads = 0 + while time.monotonic() < deadline: + layout = self.client.debug.read_layout() + if layout != previous_layout: + if layout == candidate: + stable_reads += 1 + else: + candidate = layout + stable_reads = 1 + if stable_reads >= 3: + self.client._capture_oled(layout) + return layout + else: + candidate = None + stable_reads = 0 + time.sleep(0.025) + + raise RuntimeError( + 'OLED did not reach a stable changed seed-ceremony screen') + + def _reset_without_pin_and_capture(self, strength): external_entropy = b'zlutoucky kun upel divoke ody' * 2 - strength = 128 - ret = self.client.call_raw(proto.ResetDevice(display_random=False, strength=strength, passphrase_protection=False, @@ -73,6 +147,7 @@ def test_reset_device(self): # Provide entropy self.assertIsInstance(ret, proto.EntropyRequest) internal_entropy = self.client.debug.read_reset_entropy() + previous_layout = self._current_layout_for_capture() resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy)) # Generate mnemonic locally @@ -81,31 +156,33 @@ def test_reset_device(self): # Explainer Dialog self.assertIsInstance(resp, proto.ButtonRequest) + previous_layout = self._capture_after_stable_transition(previous_layout) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = [] while isinstance(resp, proto.ButtonRequest): - mnemonic.append(self.client.debug.read_reset_word()) - if len(mnemonic) == 1: - # Manual call_raw() flow: bind the report evidence to a word - # the DebugLink confirms is currently on the device. - self.client.capture_oled() + previous_layout = self._capture_after_stable_transition( + previous_layout) + words = self.client.debug.read_reset_word() + # 7.14.2's debug build exposes each physical subpage as a separate + # ButtonRequest for evidence capture. All subpages in one legacy + # word group intentionally report the same reset_word value. + if not mnemonic or mnemonic[-1] != words: + mnemonic.append(words) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = ' '.join(mnemonic) - # Compare that device generated proper mnemonic for given entropies self.assertEqual(mnemonic, expected_mnemonic) - self.assertIsInstance(resp, proto.Success) + self.assertEqual(strength // 32 * 3, len(mnemonic.split())) + return self.client.call_raw(proto.Initialize()) - # Compare that second pass printed out the same mnemonic once again - self.assertEqual(mnemonic, expected_mnemonic) - - # Check if device is properly initialized - resp = self.client.call_raw(proto.Initialize()) + def test_reset_device(self): + # 128-bit entropy produces the 12-word ceremony. + resp = self._reset_without_pin_and_capture(128) self.assertFalse(resp.pin_protection) self.assertFalse(resp.passphrase_protection) @@ -117,77 +194,115 @@ def test_reset_device(self): resp = self.client.call_raw(proto.Ping(pin_protection=True)) self.assertIsInstance(resp, proto.Success) - def test_reset_device_dice(self): - # On-device dice entry landed after the RC18 candidate. RC18 accepts - # the forward-compatible field but follows the ordinary entropy flow. - self.requires_firmware(self.POST_RC18_SETUP_FIRMWARE) - - external_entropy = b'zlutoucky kun upel divoke ody' * 2 - strength = 256 # 99 rolls - - ret = self.client.call_raw(proto.ResetDevice(display_random=False, - strength=strength, - passphrase_protection=False, - pin_protection=False, - language='english', - label='dice', - dice_entropy=True)) - - # Device announces the on-device dice entry screen - self.assertIsInstance(ret, proto.ButtonRequest) - self.assertEqual(ret.code, proto_types.ButtonRequest_DiceRoll) - self.client.capture_oled() - - # Ack without blocking on the reply: the device only leaves the dice - # screen once the rolls are complete, and input is ignored until the - # ButtonRequest is acked. - self.client.transport.write(proto.ButtonAck()) - time.sleep(0.3) - - # Inject rolls in max_size-40 chunks, exercising undo ('u') along the - # way. Simulate the same rules host-side to know the expected string. + def _inject_rolls(self, target): + """Inject rolls in max_size-40 chunks, exercising undo ('u') along + the way, and simulate the same rules host-side to know the string + the device saw. Extras past `target` are dropped, as on the device. + The pattern stays close to uniform so it passes the 30%-per-face + bias gate for both the 50- and 99-roll targets.""" chunks = [ "123456" * 6 + "1234", # 40 digits "654321" * 6 + "43u2", # 39 digits + undo "1234561234561234561u2u3", # more undo churn - "555555555555555555555555", # top up past 99 (extras dropped) + "612345612345612345612345", # top up past target ] expected = [] for chunk in chunks: + # Mirror dice_input_collect() exactly: it stops consuming a chunk + # the moment the target is reached -- undo included -- and leaves + # the roll screen at that moment. A chunk sent after that would + # arrive at the digest confirm as a "no" decision, so stop too. for c in chunk: + if len(expected) >= target: + break if c == 'u': if expected: expected.pop() - elif len(expected) < 99: + else: expected.append(c) self.client.debug.press_input(chunk) time.sleep(0.2) + if len(expected) >= target: + break expected = ''.join(expected) - self.assertEqual(len(expected), 99) + self.assertEqual(len(expected), target) + return expected + + def _dice_reset(self, dice_only, strength, external_entropy): + """Drive a dice ResetDevice in the mode the host selects. + + dice_entropy alone is MIXED; with dice_only it is ONLY. Returns + (device_words, rolls, mnemonic, final_resp); device_words is the + 24-word device-entropy sentence MIXED shows before rolling, else ''. + """ + rolls_needed = {128: 50, 192: 75, 256: 99}[strength] + + previous_layout = self._current_layout_for_capture() + ret = self.client.call_raw(proto.ResetDevice(display_random=False, + strength=strength, + passphrase_protection=False, + pin_protection=False, + language='english', + label='dice', + dice_entropy=True, + dice_only=dice_only)) - # Rolls complete -> digest confirmation screen + # The consent screen names the mode the host asked for. It is a + # plain confirm: holding proceeds, and the only "no" is cancelling + # the reset, which is the right answer to a mode the user did not + # choose. + self.assertIsInstance(ret, proto.ButtonRequest) + self.assertEqual(ret.code, proto_types.ButtonRequest_DiceRoll) + consent_layout = self._capture_after_stable_transition(previous_layout) + self.client.debug.press_yes() + resp = self.client.call_raw(proto.ButtonAck()) + + # MIXED shows the device-entropy words BEFORE the rolls, one DiceRoll + # request per page, readable over DebugLink. The roll screen reads + # back empty, which is how this loop knows the pages are over. + device_words = [] + while True: + self.assertIsInstance(resp, proto.ButtonRequest) + self.assertEqual(resp.code, proto_types.ButtonRequest_DiceRoll) + words = self.client.debug.read_reset_word() + if not words: + break + if not device_words or device_words[-1] != words: + device_words.append(words) + self.client.debug.press_yes() + resp = self.client.call_raw(proto.ButtonAck()) + dice_entry_layout = self._capture_after_stable_transition(consent_layout) + + self.client.transport.write(proto.ButtonAck()) + time.sleep(0.3) + rolls = self._inject_rolls(rolls_needed) + + # Rolls complete -> full-digest confirmation screen resp = self.client.transport.read_blocking() self.assertIsInstance(resp, proto.ButtonRequest) self.assertEqual(resp.code, proto_types.ButtonRequest_DiceRoll) + self._capture_after_stable_transition(dice_entry_layout) # The device-computed digest must cover exactly the injected rolls - dice_digest = self.client.debug.read_dice_digest() - self.assertEqual(dice_digest, - hashlib.sha256(expected.encode('ascii')).digest()) - self.client.capture_oled() - - self.client.debug.press_yes() - ret = self.client.call_raw(proto.ButtonAck()) + self.assertEqual(self.client.debug.read_dice_digest(), + hashlib.sha256(rolls.encode('ascii')).digest()) + + # The full digest pages locally under one request on hardware, but + # under DEBUG_LINK every subpage after a debug decision raises its own + # ButtonRequest, exactly as the backup pager does. Hold through all of + # them; how many there are depends on the digest's glyph widths. + ret = resp + while isinstance(ret, proto.ButtonRequest): + self.assertEqual(ret.code, proto_types.ButtonRequest_DiceRoll) + self.client.debug.press_yes() + ret = self.client.call_raw(proto.ButtonAck()) - # From here the flow is the standard one: the displayed internal - # entropy is the post-dice-mix value and still binds the seed. + # The wire flow is unchanged: EntropyRequest is still sent and its ack + # consumed. Its bytes must not reach the seed, which the callers prove + # by computing the expected mnemonic without them. self.assertIsInstance(ret, proto.EntropyRequest) - internal_entropy = self.client.debug.read_reset_entropy() resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy)) - entropy = generate_entropy(strength, internal_entropy, external_entropy) - expected_mnemonic = Mnemonic('english').to_mnemonic(entropy) - # Explainer dialog, then the paginated backup self.assertIsInstance(resp, proto.ButtonRequest) self.client.debug.press_yes() @@ -195,12 +310,152 @@ def test_reset_device_dice(self): mnemonic = [] while isinstance(resp, proto.ButtonRequest): - mnemonic.append(self.client.debug.read_reset_word()) + words = self.client.debug.read_reset_word() + # Debug subpages repeat their logical word group, as in the + # normal reset collector above. Keep the final seed assertion. + if not mnemonic or mnemonic[-1] != words: + mnemonic.append(words) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) + return ' '.join(device_words), rolls, ' '.join(mnemonic), resp + + def test_reset_device_dice_mixed_is_verifiable(self): + self.requires_dice_modes() + + external_entropy = b'zlutoucky kun upel divoke ody' * 2 + strength = 256 # 99 rolls, 24 words + + device_words, rolls, mnemonic, resp = self._dice_reset( + False, strength, external_entropy) self.assertIsInstance(resp, proto.Success) - self.assertEqual(' '.join(mnemonic), expected_mnemonic) + + # The device committed its 32-byte draw as 24 valid BIP-39 words + # before it had seen a single roll. + self.assertEqual(24, len(device_words.split())) + device_entropy = bip39_words_to_entropy(device_words) + + # Recompute the seed from exactly what a user holds -- the words they + # copied and the rolls they made -- with the host's EntropyAck bytes + # nowhere in it. A match proves the device used both and ignored the + # host; the expected value comes from the formula, not the device. + seed = dice_mixed_seed(device_entropy, rolls) + self.assertEqual( + mnemonic, Mnemonic('english').to_mnemonic(seed[:strength // 8])) + self.assertEqual(24, len(mnemonic.split())) + + def test_reset_device_dice_only_is_verifiable(self): + self.requires_dice_modes() + + # A nonzero, known host contribution, so a device that mixed it in + # would produce a different sentence and fail below. + external_entropy = b'host bytes that must be ignored' * 2 + strength = 128 # 50 rolls, 12 words: the shorter target too + + device_words, rolls, mnemonic, resp = self._dice_reset( + True, strength, external_entropy) + self.assertIsInstance(resp, proto.Success) + + # Nothing to copy down: the rolls are the entire derivation. + self.assertEqual('', device_words) + seed = dice_only_seed(rolls) + self.assertEqual( + mnemonic, Mnemonic('english').to_mnemonic(seed[:strength // 8])) + self.assertEqual(12, len(mnemonic.split())) + + def test_reset_device_dice_rejects_biased_rolls(self): + self.requires_dice_modes() + + ret = self.client.call_raw(proto.ResetDevice(display_random=False, + strength=128, + passphrase_protection=False, + pin_protection=False, + language='english', + label='dice', + dice_entropy=True, + dice_only=True)) + self.assertIsInstance(ret, proto.ButtonRequest) + self.client.debug.press_yes() + resp = self.client.call_raw(proto.ButtonAck()) + self.assertIsInstance(resp, proto.ButtonRequest) + self.assertEqual(resp.code, proto_types.ButtonRequest_DiceRoll) + self.client.transport.write(proto.ButtonAck()) + time.sleep(0.3) + + # Fifty ones: one face on 100% of the rolls. Coldcard's rule refuses + # anything over 30%, and so does the device -- before it shows a + # digest, so a loaded die never becomes a wallet. + self.client.debug.press_input('1' * 40) + time.sleep(0.2) + self.client.debug.press_input('1' * 10) + time.sleep(0.2) + + resp = self.client.transport.read_blocking() + self.assertIsInstance(resp, proto.Failure) + self.assertEqual(resp.code, proto_types.Failure_SyntaxError) + + def test_reset_device_dice_only_requires_dice_entropy(self): + self.requires_dice_modes() + + # dice_only is a modifier of the dice ceremony, not a ceremony of its + # own. Refused before any screen, so a host cannot reach the + # rolls-only derivation without also asking for the rolls. + ret = self.client.call_raw(proto.ResetDevice(display_random=False, + strength=128, + passphrase_protection=False, + pin_protection=False, + language='english', + label='dice', + dice_entropy=False, + dice_only=True)) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_SyntaxError) + + def test_reset_device_dice_refuses_no_backup(self): + self.requires_dice_modes() + + # The dice modes exist to be checked against the backup words; a reset + # that never shows them has nothing to verify and would put seed + # material on the screen under a WARNING that recovery is impossible. + ret = self.client.call_raw(proto.ResetDevice(display_random=False, + strength=128, + passphrase_protection=False, + pin_protection=False, + language='english', + label='dice', + no_backup=True, + dice_entropy=True)) + self.assertIsInstance(ret, proto.Failure) + self.assertEqual(ret.code, proto_types.Failure_SyntaxError) + + def test_reset_device_dice_consent_cancel_aborts(self): + self.requires_dice_modes() + + # The consent screen's only "no" is the host's Cancel. It must abort + # the whole ceremony: nothing armed, nothing staged, device still + # uninitialized. + ret = self.client.call_raw(proto.ResetDevice(display_random=False, + strength=128, + passphrase_protection=False, + pin_protection=False, + language='english', + label='dice', + dice_entropy=True, + dice_only=True)) + self.assertIsInstance(ret, proto.ButtonRequest) + self.assertEqual(ret.code, proto_types.ButtonRequest_DiceRoll) + + resp = self.client.call_raw(proto.Cancel()) + self.assertIsInstance(resp, proto.Failure) + self.assertEqual(resp.code, proto_types.Failure_ActionCancelled) + + # An EntropyAck after the abort finds no armed ceremony to consume it. + resp = self.client.call_raw(proto.EntropyAck(entropy=b'\x42' * 32)) + self.assertIsInstance(resp, proto.Failure) + + features = self.client.call_raw(proto.Initialize()) + self.assertIsInstance(features, proto.Features) + self.assertFalse(features.initialized) def test_reset_reentry_disarms_entropy_ack(self): """An abandoned reset must never leave EntropyAck armed. @@ -219,8 +474,9 @@ def test_reset_reentry_disarms_entropy_ack(self): disarmed -- there is no second ceremony to leave armed. Both halves are asserted below: the refusal, and then the original property. """ - # The single armed-ceremony guard is the post-RC18 #429 behavior. - self.requires_firmware(self.POST_RC18_SETUP_FIRMWARE) + # 7.14.3: the bitcoin-only release line carries the same single-armed + # ceremony and the dice backport; see test_reset_device_dice. + self.requires_firmware("7.14.3") self.client.wipe_device() # Arm a reset and walk away without acking the entropy request. @@ -258,9 +514,25 @@ def test_reset_reentry_disarms_entropy_ack(self): ret = self.client.call_raw(proto.Initialize()) self.assertFalse(ret.initialized) + def test_reset_device_18_words(self): + resp = self._reset_without_pin_and_capture(192) + self.assertFalse(resp.pin_protection) + self.assertFalse(resp.passphrase_protection) + + def test_reset_device_24_words(self): + resp = self._reset_without_pin_and_capture(256) + self.assertFalse(resp.pin_protection) + self.assertFalse(resp.passphrase_protection) + def test_reset_device_pin(self): external_entropy = b'zlutoucky kun upel divoke ody' * 2 strength = 128 + # display_random is ignored by every supported product. 7.14.2 always + # did; 7.14.3 and 7.15 now do too. The request below deliberately sets + # it to True so this test fails if any firmware starts honouring it + # again: the device half it would render is the exact 32 bytes whose + # complement this host supplies, so the screen plus our own + # external_entropy is the seed pre-image. ret = self.client.call_raw(proto.ResetDevice(display_random=True, strength=strength, @@ -269,28 +541,18 @@ def test_reset_device_pin(self): language='english', label='test')) - # display_random=True above is deliberate: the field stays in the wire - # schema for host compatibility. The post-RC18 setup hardening (fw - # 320f0eb5, "no entropy display"), first shipped on 7.16, stopped - # honouring it -- internal entropy is seed - # pre-image material, and a host that sets the flag and reads that - # screen once can compute SHA256(shown || ext) and derive the seed. - # - # Branch on the version rather than skipping the test: everything below - # (PIN entry, EntropyRequest/Ack, mnemonic derivation) is version- - # independent and must keep running on older firmware. - f = self.client.features - if (f.major_version, f.minor_version, f.patch_version) < (7, 16, 0): - # RC18 and older: the Internal Entropy screen still exists. - self.assertIsInstance(ret, proto.ButtonRequest) - self.client.debug.press_yes() - ret = self.client.call_raw(proto.ButtonAck()) + self.assertNotIsInstance( + ret, proto.ButtonRequest, + 'display_random must be ignored: firmware answered the reset with a ' + 'ButtonRequest, which means an internal-entropy screen was drawn') self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for first time pin_encoded = self.client.debug.encode_pin('654') ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for second time pin_encoded = self.client.debug.encode_pin('654') @@ -299,6 +561,7 @@ def test_reset_device_pin(self): # Provide entropy self.assertIsInstance(ret, proto.EntropyRequest) internal_entropy = self.client.debug.read_reset_entropy() + previous_layout = self._current_layout_for_capture() resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy)) # Generate mnemonic locally @@ -307,12 +570,17 @@ def test_reset_device_pin(self): # Explainer Dialog self.assertIsInstance(resp, proto.ButtonRequest) + previous_layout = self._capture_after_stable_transition(previous_layout) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) mnemonic = [] while isinstance(resp, proto.ButtonRequest): - mnemonic.append(self.client.debug.read_reset_word()) + previous_layout = self._capture_after_stable_transition( + previous_layout) + words = self.client.debug.read_reset_word() + if not mnemonic or mnemonic[-1] != words: + mnemonic.append(words) self.client.debug.press_yes() resp = self.client.call_raw(proto.ButtonAck()) @@ -346,6 +614,12 @@ def test_reset_device_pin(self): def test_failed_pin(self): external_entropy = 'zlutoucky kun upel divoke ody' * 2 strength = 128 + # display_random is ignored by every supported product. 7.14.2 always + # did; 7.14.3 and 7.15 now do too. The request below deliberately sets + # it to True so this test fails if any firmware starts honouring it + # again: the device half it would render is the exact 32 bytes whose + # complement this host supplies, so the screen plus our own + # external_entropy is the seed pre-image. ret = self.client.call_raw(proto.ResetDevice(display_random=True, strength=strength, @@ -354,28 +628,18 @@ def test_failed_pin(self): language='english', label='test')) - # display_random=True above is deliberate: the field stays in the wire - # schema for host compatibility. The post-RC18 setup hardening (fw - # 320f0eb5, "no entropy display"), first shipped on 7.16, stopped - # honouring it -- internal entropy is seed - # pre-image material, and a host that sets the flag and reads that - # screen once can compute SHA256(shown || ext) and derive the seed. - # - # Branch on the version rather than skipping the test: everything below - # (PIN entry, EntropyRequest/Ack, mnemonic derivation) is version- - # independent and must keep running on older firmware. - f = self.client.features - if (f.major_version, f.minor_version, f.patch_version) < (7, 16, 0): - # RC18 and older: the Internal Entropy screen still exists. - self.assertIsInstance(ret, proto.ButtonRequest) - self.client.debug.press_yes() - ret = self.client.call_raw(proto.ButtonAck()) + self.assertNotIsInstance( + ret, proto.ButtonRequest, + 'display_random must be ignored: firmware answered the reset with a ' + 'ButtonRequest, which means an internal-entropy screen was drawn') self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for first time pin_encoded = self.client.debug.encode_pin(self.pin4) ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded)) self.assertIsInstance(ret, proto.PinMatrixRequest) + self.client._capture_oled_after_animation(1.05, (192, 256, 0, 64)) # Enter PIN for second time pin_encoded = self.client.debug.encode_pin(self.pin6) diff --git a/tests/test_msg_ripple_get_address.py b/tests/test_msg_ripple_get_address.py index 0b0fb8f1..8ac0dcd0 100644 --- a/tests/test_msg_ripple_get_address.py +++ b/tests/test_msg_ripple_get_address.py @@ -35,6 +35,18 @@ def test_ripple_get_address(self): address = self.client.ripple_get_address(parse_path("m/44'/144'/1'/0/0")) self.assertEqual(address, "rJX2KwzaLJDyFhhtXKi3htaLfaUH2tptEX") + def test_ripple_show_address(self): + self.requires_fullFeature() + self.requires_firmware("6.4.0") + self.setup_mnemonic_allallall() + address = self.client.ripple_get_address( + parse_path("m/44'/144'/0'/0/0"), show_display=True) + # 7.14.2 and later preserve the response across DebugLinkGetState + # requests made during screenshot capture; the same fix is on all three + # products, so the floor is the release the fix first shipped in. + if self.firmware_at_least("7.14.2"): + self.assertEqual(address, "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H") + def test_ripple_get_address_other(self): self.requires_fullFeature() self.requires_firmware("6.4.0") @@ -54,4 +66,3 @@ def test_ripple_get_address_other(self): if __name__ == '__main__': unittest.main() - diff --git a/tests/test_msg_ripple_sign_tx.py b/tests/test_msg_ripple_sign_tx.py index aaeab6cd..9ed1d183 100644 --- a/tests/test_msg_ripple_sign_tx.py +++ b/tests/test_msg_ripple_sign_tx.py @@ -100,23 +100,9 @@ def test_sign(self): ) - @unittest.skip( - "XRP memo is not a supported feature yet. A THORChain memo cannot " - "traverse hdwallet -> RippleSignTx: the protobuf has no memo field " - "(RippleSignTx carries 1-6, RipplePayment carries " - "amount/destination/destination_tag), and hdwallet's rippleSignTx " - "never reads tx.value.memo. The firmware therefore never receives it " - "and cannot serialize it. Tracked as keepkey/keepkey-vault#422.\n" - "\n" - "This assertion is CORRECT and is deliberately left intact: it " - "describes the behaviour the product needs. Do NOT make it pass by " - "asserting the memo is absent -- that would encode the bug as the " - "contract. Re-enable only when the signed serialization actually " - "preserves the memo." - ) def test_sign_with_thorchain_memo(self): self.requires_fullFeature() - self.requires_firmware("7.14.2") + self.requires_firmware("7.15.0") self.setup_mnemonic_allallall() @@ -135,7 +121,8 @@ def test_sign_with_thorchain_memo(self): resp = self.client.call(msg) # Verify the XRPL Memos array is appended to the serialized tx. - # Format: 0xF9 (STArray[9]) 0xEA (STObject[10]) 0x7D (MemoData VL[13]) + # Format: 0xF9 (STArray[9]) 0xEA (STObject[10]) 0x7D (MemoData VL[13]; + # 0x72 would be MessageKey, which rippled rejects inside a Memo) # 0xE1 (end object) 0xF1 (end array) memo_bytes = memo.encode('ascii') expected_tail = ( @@ -165,6 +152,23 @@ def test_sign_with_thorchain_memo(self): "plain send must not contain Memos array (0xF9 0xEA marker sequence)" ) + def test_unsupported_memo_is_rejected(self): + self.requires_fullFeature() + self.requires_firmware("7.14.3") + if self.firmware_at_least("7.15.0"): + self.skipTest("Ripple memos are implemented in 7.15") + self.setup_mnemonic_allallall() + msg = messages.RippleSignTx( + address_n=parse_path("m/44'/144'/0'/0/0"), + payment=messages.RipplePayment( + amount=100000000, + destination="rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws"), + flags=0x80000000, fee=100000, sequence=25, + memo="routing-memo") + with self.assertRaises(CallException) as caught: + self.client.call(msg) + self.assertEqual(caught.exception.args[0], types.Failure_SyntaxError) + def test_ripple_sign_invalid_fee(self): self.requires_fullFeature() self.requires_firmware("6.4.0") diff --git a/tests/test_msg_session_trust_lifetime.py b/tests/test_msg_session_trust_lifetime.py index ec79042d..23e5d293 100644 --- a/tests/test_msg_session_trust_lifetime.py +++ b/tests/test_msg_session_trust_lifetime.py @@ -198,9 +198,9 @@ def _resolve_executable(pid, comm, cwd): class TestSessionTrustLifetime(common.KeepKeyTest): - # RC18 still persisted AdvancedMode and retained runtime signers across - # session teardown. The session-lifetime fixes first ship in 7.16. - MIN_FIRMWARE = "7.16.0" + # Canonical 7.15 makes AdvancedMode and runtime signer trust session-only. + # Its release contract requires these lifetime checks. + MIN_FIRMWARE = "7.15.0" def setUp(self): super(TestSessionTrustLifetime, self).setUp() diff --git a/tests/test_msg_signing_boundaries.py b/tests/test_msg_signing_boundaries.py new file mode 100644 index 00000000..ce56f8f2 --- /dev/null +++ b/tests/test_msg_signing_boundaries.py @@ -0,0 +1,204 @@ +# This file is part of the TREZOR project. +# +# Copyright (C) 2026 KeepKey +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +from __future__ import print_function + +import binascii +import unittest + +import common +import keepkeylib.ckd_public as ckd_public +import keepkeylib.messages_pb2 as proto +import keepkeylib.types_pb2 as proto_types +from keepkeylib.client import CallException + + +class TestSigningBoundaries(common.KeepKeyTest): + PREV_HASH = binascii.unhexlify( + 'd5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882') + XPUB = ( + 'xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyW' + 'fskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy') + + def _input(self): + return proto_types.TxInputType( + address_n=[0], + prev_hash=self.PREV_HASH, + prev_index=0, + ) + + def _ordinary_output(self): + return proto_types.TxOutputType( + address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1', + amount=380000, + script_type=proto_types.PAYTOADDRESS, + ) + + @staticmethod + def _request_key(request): + return ( + request.request_type, + request.details.request_index, + bytes(request.details.tx_hash), + request.details.extra_data_offset, + request.details.extra_data_len, + ) + + def _assert_late_txack_rejected(self): + response = self.client.call_raw( + proto.TxAck(tx=proto_types.TransactionType())) + self.assertIsInstance(response, proto.Failure) + self.assertEqual(response.code, proto_types.Failure_UnexpectedMessage) + + def test_clear_session_aborts_every_txrequest_stage(self): + self.setup_mnemonic_nopin_nopassphrase() + + stage_trace = [] + + def record_stage(request, message): + stage_trace.append(self._request_key(request)) + return message + + signatures, serialized_tx = self.client.sign_tx( + 'Bitcoin', [self._input()], [self._ordinary_output()], + debug_processor=record_stage) + self.assertTrue(signatures[0]) + self.assertTrue(serialized_tx) + self.assertTrue(stage_trace) + self.assertIn(proto_types.TXMETA, + [stage[0] for stage in stage_trace]) + self.assertIn(proto_types.TXINPUT, + [stage[0] for stage in stage_trace]) + self.assertIn(proto_types.TXOUTPUT, + [stage[0] for stage in stage_trace]) + + for target_index, expected_stage in enumerate(stage_trace): + seen = [] + + def clear_at_target(request, message): + seen.append(self._request_key(request)) + if len(seen) - 1 == target_index: + response = self.client.call_raw(proto.ClearSession()) + self.assertIsInstance(response, proto.Success) + return message + + with self.assertRaises(CallException): + self.client.sign_tx( + 'Bitcoin', [self._input()], [self._ordinary_output()], + debug_processor=clear_at_target) + + self.assertEqual(seen[-1], expected_stage) + self.assertEqual(len(seen), target_index + 1) + self._assert_late_txack_rejected() + + def _invalid_multisig(self, m, n): + node = ckd_public.deserialize(self.XPUB) + return proto_types.MultisigRedeemScriptType( + pubkeys=[ + proto_types.HDNodePathType(node=node, address_n=[i + 1]) + for i in range(n) + ], + signatures=[b''] * n, + m=m, + ) + + def test_invalid_multisig_outputs_never_serialize_or_sign(self): + self.setup_mnemonic_nopin_nopassphrase() + + invalid_quorums = ( + (0, 1), # m == 0 + (1, 0), # n == 0 + (2, 1), # m > n + (16, 15), # m > 15 + (1, 16), # n > 15 + ) + + for internal in (False, True): + for m, n in invalid_quorums: + output = proto_types.TxOutputType( + address_n=[1] if internal else [], + amount=380000, + script_type=proto_types.PAYTOMULTISIG, + multisig=self._invalid_multisig(m, n), + ) + signed_material = [] + + def observe_response(request, message): + if request.HasField('serialized'): + serialized = request.serialized + if (serialized.HasField('serialized_tx') or + serialized.HasField('signature')): + signed_material.append(serialized) + return message + + with self.assertRaises(CallException): + self.client.sign_tx( + 'Bitcoin', [self._input()], [output], + debug_processor=observe_response) + + self.assertEqual(signed_material, []) + response = self.client.call_raw( + proto.TxAck(tx=proto_types.TransactionType())) + self.assertIsInstance(response, proto.Failure) + self.client.call_raw(proto.ClearSession()) + + def test_multisig_signature_over_72_bytes_is_rejected(self): + """An oversized signature must fail decoding and terminate signing.""" + self.requires_firmware("7.14.2") + self.setup_mnemonic_nopin_nopassphrase() + node = ckd_public.deserialize(self.XPUB) + multisig = proto_types.MultisigRedeemScriptType( + pubkeys=[ + proto_types.HDNodePathType(node=node, address_n=[1]), + proto_types.HDNodePathType(node=node, address_n=[2]), + proto_types.HDNodePathType(node=node, address_n=[3]), + ], + signatures=[b"\x30" * 74, b"", b""], + m=2, + ) + tx_input = proto_types.TxInputType( + address_n=[1], + prev_hash=binascii.unhexlify( + "c6091adf4c0c23982a35899a6e58ae11" + "e703eacd7954f588ed4b9cdefc4dba52" + ), + prev_index=1, + script_type=proto_types.SPENDMULTISIG, + multisig=multisig, + ) + + first = self.client.call_raw(proto.SignTx( + inputs_count=1, outputs_count=1, coin_name="Bitcoin" + )) + self.assertIsInstance(first, proto.TxRequest) + rejected = self.client.call_raw(proto.TxAck( + tx=proto_types.TransactionType(inputs=[tx_input]) + )) + self.assertIsInstance(rejected, proto.Failure) + self.assertEqual(rejected.code, proto_types.Failure_UnexpectedMessage) + self.assertEqual(rejected.message, "Could not parse protocol buffer message") + self._assert_late_txack_rejected() + + def test_clear_session_aborts_active_bitcoin_signing(self): + """Authorization loss destroys a signer before its first TxAck.""" + self.requires_firmware("7.14.2") + self.setup_mnemonic_nopin_nopassphrase() + first = self.client.call_raw(proto.SignTx( + inputs_count=1, outputs_count=1, coin_name="Bitcoin" + )) + self.assertIsInstance(first, proto.TxRequest) + cleared = self.client.call_raw(proto.ClearSession()) + self.assertIsInstance(cleared, proto.Success) + self._assert_late_txack_rejected() + features = self.client.call_raw(proto.Initialize()) + self.assertIsInstance(features, proto.Features) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_signtx_ethereum_erc20.py b/tests/test_msg_signtx_ethereum_erc20.py index ef03f0b4..4c13aa4c 100644 --- a/tests/test_msg_signtx_ethereum_erc20.py +++ b/tests/test_msg_signtx_ethereum_erc20.py @@ -71,6 +71,20 @@ def test_approve_all(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() + if self.firmware_at_least("7.14.2"): + with self.assertRaises(CallException): + self.client.ethereum_sign_tx( + n=[2147483692,2147483708,2147483648,0,0], + nonce=1, + gas_price=20, + gas_limit=20, + value=0, + to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), + chain_id=1, + data=binascii.unhexlify('095ea7b3000000000000000000000000' + '1d1c328764a41bda0492b66baa30c4a339ff85ef' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + ) + return + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( n=[2147483692,2147483708,2147483648,0,0], nonce=1, diff --git a/tests/test_msg_signtx_taproot.py b/tests/test_msg_signtx_taproot.py index 7dcc3cd5..1f1d0fc4 100644 --- a/tests/test_msg_signtx_taproot.py +++ b/tests/test_msg_signtx_taproot.py @@ -26,25 +26,26 @@ -# Synthetic prev tx paying 100000 sat to the BIP-86 first receiving address of -# the "abandon abandon ... about" mnemonic -# (bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr). -# The fixture lives in tests/txcache and was produced together with the -# expected witness below by an independent Python implementation of -# BIP-340/341, keyed from BIP-86's own published xprv. -PREV_TXID = "6e32033911982f7550ab1d26232adfd08711293e15085f77cd27628be0a6ee37" +# Canonical fixture paying 100000 sat to the BIP-86 first receiving address of +# the "abandon abandon ... about" mnemonic. The device requests the previous +# transaction even though Taproot signing also receives the amount and derives +# the prevout script from the path, so this must name a real, hash-consistent +# transaction from txcache rather than a synthetic outpoint. The expected +# witnesses below were independently checked against BIP-341 sighashes with a +# BIP-340 verifier keyed from BIP-86's published xprv. +PREV_TXID = "3e1fdf082678a8a2f378995ffc0e4f853942c55c4ddbc2771b348413eeeca9a4" IN_AMOUNT = 100000 OUT_AMOUNT = 90000 OUT_ADDRESS = "1BitcoinEaterAddressDontSendf59kuE" EXPECTED_WITNESS = ( - "afe221b16d648a1ad7329f9765930732380cc67765bd73af7ce13b5991146851" - "2d9ee77e34af56fe1f59f98372011f7cb400ced614d808c690c5ba907fb62de9" + "e11beb22fd50225a4fa53a61738993cc742cc6a2361faea0313b0b456300669c" + "2d9ebd503e11855e5bc8018d7bfd5122d578470e1e4e65820705db595724f9eb" ) EXPECTED_CHANGE_WITNESS = ( - "e3c44408fe61256ad406733f100f1ee856eb31854335efa59e60a61ea5d41ab" - "341802f0cccb55f644042a1ab390f0a406b9d3efe3996d05442b4ee43d5355eab" + "ed37247c670b8b260f2c5a619c8f1443493ea6f1eb6230adce5fbafa4b3067e1" + "879a905d40db728c1771207843b2ec03a40484975653e29e583cfc0964d0c95c" ) EXPECTED_CHANGE_SCRIPT = ( "5120882d74e5d0572d5a816cef0041a96b6c1de832f6f9676d9605c44d5e9a97d3dc" @@ -65,19 +66,19 @@ # `signature` alone was populated correctly even while the witness and the # locktime footer were being dropped on the wire. EXPECTED_SERIALIZED_TX = ( - "0100000000010137eea6e08b6227cd775f08153e291187d0df2a23261dab50752f98" - "113903326e0000000000ffffffff01905f0100000000001976a914759d6677091e97" - "3b9e9d99f19c68fbf43e3f05f988ac0140afe221b16d648a1ad7329f976593073238" - "0cc67765bd73af7ce13b59911468512d9ee77e34af56fe1f59f98372011f7cb400ce" - "d614d808c690c5ba907fb62de900000000" + "01000000000101a4a9ecee1384341b77c2db4d5cc54239854f0efc5f9978f3a2a878" + "2608df1f3e0000000000ffffffff01905f0100000000001976a914759d6677091e973b" + "9e9d99f19c68fbf43e3f05f988ac0140e11beb22fd50225a4fa53a61738993cc742c" + "c6a2361faea0313b0b456300669c2d9ebd503e11855e5bc8018d7bfd5122d578470e" + "1e4e65820705db595724f9eb00000000" ) EXPECTED_SERIALIZED_TX_CHANGE = ( - "0100000000010137eea6e08b6227cd775f08153e291187d0df2a23261dab50752f98" - "113903326e0000000000ffffffff0250c30000000000001976a914759d6677091e97" - "3b9e9d99f19c68fbf43e3f05f988ac409c000000000000225120882d74e5d0572d5a" - "816cef0041a96b6c1de832f6f9676d9605c44d5e9a97d3dc0140e3c44408fe61256a" - "d406733f100f1ee856eb31854335efa59e60a61ea5d41ab341802f0cccb55f644042" - "a1ab390f0a406b9d3efe3996d05442b4ee43d5355eab00000000" + "01000000000101a4a9ecee1384341b77c2db4d5cc54239854f0efc5f9978f3a2a878" + "2608df1f3e0000000000ffffffff0250c30000000000001976a914759d6677091e973b" + "9e9d99f19c68fbf43e3f05f988ac409c000000000000225120882d74e5d0572d5a81" + "6cef0041a96b6c1de832f6f9676d9605c44d5e9a97d3dc0140ed37247c670b8b260f" + "2c5a619c8f1443493ea6f1eb6230adce5fbafa4b3067e1879a905d40db728c177120" + "7843b2ec03a40484975653e29e583cfc0964d0c95c00000000" ) EXPECTED_SERIALIZED_TX_MIXED = ( "01000000000102a4a9ecee1384341b77c2db4d5cc54239854f0efc5f9978f3a2a878" diff --git a/tests/test_msg_solana_display_disclosure.py b/tests/test_msg_solana_display_disclosure.py index b43c3b80..6eaec243 100644 --- a/tests/test_msg_solana_display_disclosure.py +++ b/tests/test_msg_solana_display_disclosure.py @@ -57,12 +57,16 @@ def build_memo_tx(signer, memo): class TestSolanaDisplayDisclosure(common.KeepKeyTest): def setUp(self): super(TestSolanaDisplayDisclosure, self).setUp() - self.requires_firmware("7.16.0") self.requires_fullFeature() + self.requires_firmware("7.14.2") self.setup_mnemonic_allallall() - def _capture(self, request): - recorder = ScreenRecorder(self.client, answer=True) + def _capture(self, request, screenshot_group): + recorder = ScreenRecorder( + self.client, + answer=True, + screenshot_group=screenshot_group, + ) try: with recorder: self.client.call(request) @@ -75,8 +79,8 @@ def _assert_tail_mutation_changes_review(self, make_request): payload_b = payload_a[:96] + b"B" + payload_a[97:] self.assertEqual(payload_a[:32], payload_b[:32]) - screens_a = self._capture(make_request(payload_a)) - screens_b = self._capture(make_request(payload_b)) + screens_a = self._capture(make_request(payload_a), "payload-a") + screens_b = self._capture(make_request(payload_b), "payload-b") self.assertIsNotNone(screens_a) self.assertIsNotNone(screens_b) self.assertGreater(len(screens_a), 1) @@ -114,7 +118,8 @@ def test_offchain_format_changes_oled_review(self): version=0, message_format=0, message=payload, - ) + ), + "format-ascii", ) screens_utf8 = self._capture( solana.SolanaSignOffchainMessage( @@ -122,7 +127,8 @@ def test_offchain_format_changes_oled_review(self): version=0, message_format=1, message=payload, - ) + ), + "format-utf8", ) self.assertIsNotNone(screens_ascii) self.assertIsNotNone(screens_utf8) diff --git a/tests/test_msg_solana_instruction_disclosure.py b/tests/test_msg_solana_instruction_disclosure.py new file mode 100644 index 00000000..5f84b005 --- /dev/null +++ b/tests/test_msg_solana_instruction_disclosure.py @@ -0,0 +1,423 @@ +# This file is part of the KeepKey project. +# +# Copyright (C) 2026 KeepKey +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. + +"""Adversarial disclosure tests for security-relevant Solana instructions.""" + +import struct + +import common +import pytest + +from keepkeylib import messages_solana_pb2 as solana +from keepkeylib.client import CallException +from keepkeylib.tools import parse_path +from test_msg_display_disclosure import ScreenRecorder + + +PATH = parse_path("m/44'/501'/0'/0'") +TOKEN_PROGRAM = bytes.fromhex( + "06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9" +) +TOKEN_2022_PROGRAM = bytes.fromhex( + "06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc" +) +SYSTEM_PROGRAM = b"\x00" * 32 +STAKE_PROGRAM = bytes.fromhex( + "06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000" +) +COMPUTE_BUDGET_PROGRAM = bytes.fromhex( + "0306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a40000000" +) +VOTE_PROGRAM = bytes.fromhex( + "0761481d357474bb7c4d7624ebd3bdb3d8355e73d11043fc0da3538000000000" +) +ATA_PROGRAM = bytes.fromhex( + "8c97258f4e2489f1bb3d1029148e0d830b5a1399daff1084048e7bd8dbe9f859" +) + + +def build_tx(account_keys, required_signatures, instructions, + readonly_unsigned=1): + """Build an unsigned legacy message with explicit instruction indices.""" + tx = bytearray([0, required_signatures, 0, readonly_unsigned]) + tx.append(len(account_keys)) + for account in account_keys: + tx.extend(account) + tx.extend(b"\xbb" * 32) + tx.append(len(instructions)) + for program_index, account_indices, data in instructions: + tx.append(program_index) + tx.append(len(account_indices)) + tx.extend(account_indices) + tx.append(len(data)) + tx.extend(data) + return bytes(tx) + + +class TestSolanaInstructionDisclosure(common.KeepKeyTest): + def setUp(self): + super(TestSolanaInstructionDisclosure, self).setUp() + self.requires_fullFeature() + self.requires_firmware("7.14.2") + self.setup_mnemonic_allallall() + response = self.client.call(solana.SolanaGetAddress( + address_n=PATH, show_display=False + )) + alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + value = 0 + for char in response.address: + value = value * 58 + alphabet.index(char) + self.signer = value.to_bytes(32, "big") + + def _request(self, raw_tx): + return solana.SolanaSignTx(address_n=PATH, raw_tx=raw_tx) + + def _capture(self, raw_tx, group): + recorder = ScreenRecorder( + self.client, answer=True, screenshot_group=group + ) + try: + with recorder: + self.client.call(self._request(raw_tx)) + except CallException: + return None + return recorder.fingerprint + + def _assert_pair(self, label, raw_a, raw_b): + screens_a = self._capture(raw_a, label + "-a") + screens_b = self._capture(raw_b, label + "-b") + self.assertIsNotNone(screens_a, label + " A was refused") + self.assertIsNotNone(screens_b, label + " B was refused") + self.assertNotEqual( + screens_a, screens_b, + label + " changed signed semantics without changing OLED review", + ) + + def test_set_authority_roles_require_opaque_mode(self): + target = b"\x31" * 32 + new_authority = b"\x42" * 32 + keys = [self.signer, target, TOKEN_PROGRAM] + for role in (0, 1, 2, 3): + data = bytes([6, role, 1]) + new_authority + raw_tx = build_tx(keys, 1, [(2, [1, 0], data)]) + with pytest.raises(CallException): + self.client.call(self._request(raw_tx)) + + def test_token_2022_transfer_checked_with_hook_accounts_is_opaque(self): + mint = b"\x21" * 32 + destination = b"\x32" * 32 + hook_a = b"\x43" * 32 + hook_b = b"\x54" * 32 + data = bytes([12]) + struct.pack("I", 1)) + self.assertEqual(CERT_SCOPE1[42:75], CERT_501[42:75]) + request = self._join_request(soltoshi_join(self.signer), + [sdice_definition()]) + request.clearsign_certificate = CERT_SCOPE1 + self.assertRefused(request, INVALID_CERTIFICATE) + + def test_certified_short_schema_signature_refused(self): + """The delegate's signature without its last byte. That byte is 0x00, + so the firmware's zeroed 64-byte field holds the real signature + again; only the length check refuses it.""" + self.assertEqual(SOLTOSHI_SCHEMA_SIG[-1], 0) + request = self._join_request(soltoshi_join(self.signer), + [sdice_definition()]) + request.schema_signature = SOLTOSHI_SCHEMA_SIG[:63] + self.assertRefused(request, SCHEMA_MISMATCH) + + +class TestSolanaSchemaRuntime(SchemaReview): + + def setUp(self): + super(TestSolanaSchemaRuntime, self).setUp() + self.requires_message("LoadClearsignSigner") + signed_metadata.assert_test_key_matches_slot3() + self.client.apply_policy("AdvancedMode", True) + self.signer = self._signer() + + def _load_signers(self): + """Slots 2 and 3 hold the same CI key under different aliases.""" + for key_id, alias in ((3, "CI Test"), (2, "CI Two")): + self.client.load_clearsign_signer( + key_id=key_id, + pubkey=signed_metadata.test_signer_compressed_pubkey(), + alias=alias) + + def test_runtime_schema_refuses_transfer_companion(self): + self._load_signers() + request = solana.SolanaSignTx( + address_n=PATH, + raw_tx=relay_message(self.signer, [RELAY_IX, TRANSFER_IX]), + schema_payload=RELAY_SCHEMA, schema_signature=sign(RELAY_SCHEMA), + schema_signer_key_id=3) + with self.assertRaises(CallException) as refused: + self.client.call(request) + self.assertIn("Invalid Solana instruction schema", + str(refused.exception)) + + # Control: the same request without the Transfer is reviewed. + request.raw_tx = relay_message(self.signer, [RELAY_IX]) + response, screens = self._review(request, "runtime_relay") + self.assertEqual(len(response.signature), 64) + self.assertShows(screens, "AMOUNT", "0.996374000 SOL") + + def _join(self): + """The join with account 0 set to this device's key and the Transfer + dropped: the runtime path refuses any Transfer companion.""" + msg = bytearray(SOLTOSHI_JOIN) + msg[4:36] = self.signer + at = 4 + 32 * msg[3] + 32 + self.assertEqual(msg[at], 3) + ixs, q = [], at + 1 + for _ in range(3): + start = q + q += 2 + msg[q + 1] + q += 1 + msg[q] + ixs.append(bytes(msg[start:q])) + self.assertEqual(q, len(msg)) + return bytes(msg[:at]) + b"\x02" + ixs[0] + ixs[2] + + def test_runtime_token_amount_trust_comes_from_the_schema_signer(self): + """The schema is signed by slot 2. Slot 2's definition names and + scales the three TOKEN_AMOUNTs and the mint stays on screen; the same + definition from slot 3 verifies but is ignored, and the review is the + one with no definition at all: raw base units and the mint.""" + raw = self._join() + mint = raw[4 + 8 * 32:4 + 9 * 32] + self.assertEqual(b58encode(mint), SDICE_MINT) + definition = (b"KeepKeySolanaTokenDef/1" + mint + + struct.pack(" 8: + response = self.client.call_raw(request) + else: + response = self.client.call(request) + return response, action + + def _assert_first_input_requested(self, response): + self.assertIsInstance(response, zcash_proto.ZcashTransparentAck) + self.assertTrue(response.HasField('next_input_index')) + self.assertEqual(response.next_input_index, 0) + + def _assert_path_rejected(self, bad_path, message): + self.setup_mnemonic_allallall() + response, _ = self._start_raw_session(1) + self._assert_first_input_requested(response) + item = self._make_transparent_input(address_n=bad_path) + response = self.client.call_raw( + zcash_proto.ZcashTransparentInput(**item)) + self.assertIsInstance(response, proto.Failure) + self.assertIn(message.lower(), response.message.lower()) + + def test_hybrid_signature_verifies(self): + self.setup_mnemonic_allallall() + inputs = [self._make_transparent_input()] + pubkey = self._get_pubkey_for_path(ZEC_PATH) + + response, signatures, kwargs = self._sign(inputs) + + self.assertIsInstance(response, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(response.signatures), 0) + self.assertEqual(len(signatures), 1) + self._assert_signature(signatures[0], pubkey, kwargs, inputs, 0) + + def test_hybrid_multi_input_signatures_verify(self): + self.setup_mnemonic_allallall() + amounts = [VALUE // 2, VALUE - (VALUE // 2)] + inputs = [ + self._make_transparent_input(index=i, amount=amount) + for i, amount in enumerate(amounts) + ] + pubkey = self._get_pubkey_for_path(ZEC_PATH) + + response, signatures, kwargs = self._sign(inputs) + + self.assertIsInstance(response, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(signatures), 2) + self._assert_signature(signatures[0], pubkey, kwargs, inputs, 0) + self._assert_signature(signatures[1], pubkey, kwargs, inputs, 1) + + digest_1 = _transparent_sig_digest(inputs, [], 1) + person = b'ZcashTxHash_' + kwargs['branch_id'].to_bytes(4, 'little') + wrong_digest = _b2b( + person, + kwargs['header_digest'] + digest_1 + EMPTY_SAPLING_DIGEST + + kwargs['orchard_digest']) + self.assertFalse( + self._verify_der_signature(pubkey, wrong_digest, signatures[0]), + "input 0 signature must not verify for input 1") + + def test_wrong_key_does_not_verify(self): + self.setup_mnemonic_allallall() + path_0 = list(ZEC_PATH) + path_1 = list(ZEC_PATH[:-1]) + [1] + inputs = [self._make_transparent_input(address_n=path_0)] + pubkey_0 = self._get_pubkey_for_path(path_0) + pubkey_1 = self._get_pubkey_for_path(path_1) + self.assertNotEqual(pubkey_0, pubkey_1) + + _, signatures, kwargs = self._sign(inputs) + + self._assert_signature(signatures[0], pubkey_0, kwargs, inputs, 0) + transparent_digest = _transparent_sig_digest(inputs, [], 0) + person = b'ZcashTxHash_' + kwargs['branch_id'].to_bytes(4, 'little') + digest = _b2b( + person, + kwargs['header_digest'] + transparent_digest + + EMPTY_SAPLING_DIGEST + kwargs['orchard_digest']) + self.assertFalse( + self._verify_der_signature(pubkey_1, digest, signatures[0]), + "signature for account 0 path must not verify under another key") + + def test_rejects_wrong_purpose(self): + self._assert_path_rejected( + [H + 49, H + 133, H, 0, 0], "m/44'/133'") + + def test_rejects_wrong_coin_type(self): + self._assert_path_rejected( + [H + 44, H + 60, H, 0, 0], "m/44'/133'") + + def test_rejects_unhardened_account(self): + self._assert_path_rejected( + [H + 44, H + 133, 0, 0, 0], "account must be hardened") + + def test_rejects_wrong_account(self): + self._assert_path_rejected( + [H + 44, H + 133, H + 1, 0, 0], + "account does not match approved session") + + def test_rejects_short_path(self): + self._assert_path_rejected( + [H + 44, H + 133, H], + "m/44'/133'/account'/change/index") + + def test_rejects_bad_change(self): + self._assert_path_rejected( + [H + 44, H + 133, H, 7, 0], "change must be 0 or 1") + + def test_rejects_hardened_index(self): + self._assert_path_rejected( + [H + 44, H + 133, H, 0, H], "index must not be hardened") + + def test_orchard_before_transparent_rejected(self): + self.setup_mnemonic_allallall() + response, action = self._start_raw_session(1) + self._assert_first_input_requested(response) + + response = self.client.call_raw(zcash_proto.ZcashPCZTAction( + index=0, **action)) + + self.assertIsInstance(response, proto.Failure) + self.assertIn("transparent data not yet complete", + response.message.lower()) + + def test_rejects_out_of_order_transparent_index(self): + self.setup_mnemonic_allallall() + response, _ = self._start_raw_session(2) + self._assert_first_input_requested(response) + item = self._make_transparent_input(index=1) + + response = self.client.call_raw( + zcash_proto.ZcashTransparentInput(**item)) + + self.assertIsInstance(response, proto.Failure) + self.assertIn("index", response.message.lower()) + + def test_rejects_too_many_transparent_inputs(self): + self.setup_mnemonic_allallall() + response, _ = self._start_raw_session(100) + + self.assertIsInstance(response, proto.Failure) + self.assertIn("too many transparent inputs", response.message.lower()) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_network_policy.py b/tests/test_network_policy.py new file mode 100644 index 00000000..77e56462 --- /dev/null +++ b/tests/test_network_policy.py @@ -0,0 +1,58 @@ +"""The authoritative suite's only network capability is emulator UDP.""" + +import socket + +import pytest +import requests + + +def test_non_emulator_local_transports_are_denied(): + tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + with pytest.raises(AssertionError): + tcp.connect(("127.0.0.1", 11044)) + finally: + tcp.close() + + udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + with pytest.raises(AssertionError): + udp.sendto(b"probe", ("127.0.0.1", 1)) + finally: + udp.close() + + if hasattr(socket, "AF_UNIX"): + unix = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + with pytest.raises(AssertionError): + unix.connect("/tmp/keepkey-network-policy-probe") + finally: + unix.close() + + with pytest.raises(AssertionError): + requests.get("http://127.0.0.1:1/forbidden") + + +def test_owned_emulator_lease_allows_only_its_udp_pair_and_expires(): + from emulator_endpoints import owned_emulator_pair + + receiver = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + receiver.bind(("127.0.0.1", 0)) + receiver.settimeout(1) + port = receiver.getsockname()[1] + if port == 65535: + pytest.skip("allocated port has no adjacent debug port") + with owned_emulator_pair(port): + sender.sendto(b"owned", ("127.0.0.1", port)) + assert receiver.recv(5) == b"owned" + with pytest.raises(AssertionError): + sender.sendto(b"forbidden", ("192.0.2.1", port)) + with pytest.raises(AssertionError): + sender.sendto(b"forbidden", ("127.0.0.1", 1)) + with pytest.raises(AssertionError): + sender.sendto(b"expired", ("127.0.0.1", port)) + finally: + sender.close() + receiver.close() diff --git a/tests/test_protection_levels.py b/tests/test_protection_levels.py index 891db147..0a1f377c 100644 --- a/tests/test_protection_levels.py +++ b/tests/test_protection_levels.py @@ -127,16 +127,28 @@ def test_reset_device(self): self.assertRaises(Exception, self.client.reset_device, False, 128, True, False, 'label', 'english') def test_sign_message(self): + authentication_first = self.firmware_at_least("7.14.2") with self.client: self.setup_mnemonic_pin_passphrase() self.client.clear_session() - self.client.set_expected_responses([ - proto.ButtonRequest(), - proto.PinMatrixRequest(), - proto.PassphraseRequest(), - proto.ButtonRequest(), - proto.MessageSignature(), - ]) + if authentication_first: + expected_responses = [ + proto.PinMatrixRequest(), + proto.PassphraseRequest(), + proto.ButtonRequest(), + proto.ButtonRequest( + code=proto_types.ButtonRequest_SignMessage), + proto.MessageSignature(), + ] + else: + expected_responses = [ + proto.ButtonRequest(), + proto.PinMatrixRequest(), + proto.PassphraseRequest(), + proto.ButtonRequest(), + proto.MessageSignature(), + ] + self.client.set_expected_responses(expected_responses) self.client.sign_message('Bitcoin', [], 'testing message') def test_verify_message(self): diff --git a/tests/test_report_variant_validation.py b/tests/test_report_variant_validation.py new file mode 100644 index 00000000..10f91668 --- /dev/null +++ b/tests/test_report_variant_validation.py @@ -0,0 +1,61 @@ +import importlib.util +import os +import unittest + + +REPORT_SCRIPT = os.path.join( + os.path.dirname(__file__), '..', 'scripts', 'generate-test-report.py') +SPEC = importlib.util.spec_from_file_location('generate_test_report', + REPORT_SCRIPT) +REPORT = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(REPORT) + + +def catalog_results_with_solana_lut_skipped(fw_version): + results = {} + for _, _, min_fw, _, _, tests in REPORT.SECTIONS: + if not REPORT.ver_ge(fw_version, min_fw): + continue + for _, module, method, _, _, _ in tests: + results['%s::%s' % (module, method)] = 'pass' + for key in list(results): + if key.startswith('test_msg_solana_lut_attestation::'): + results[key] = 'skip' + return results + + +class TestReportVariantValidation(unittest.TestCase): + + def test_full_7143_accepts_unimplemented_solana_lut_skip(self): + result = REPORT.validate_junit( + '7.14.3', catalog_results_with_solana_lut_skipped('7.14.3'), + 'full') + self.assertEqual((True, []), result) + + def test_full_715_requires_solana_lut_coverage(self): + ok, failures = REPORT.validate_junit( + '7.15.0', catalog_results_with_solana_lut_skipped('7.15.0'), + 'full') + self.assertFalse(ok) + self.assertEqual(4, len(failures)) + self.assertTrue(all(item[3] == 'skipped-but-required' + for item in failures)) + + def test_full_716_requires_solana_lut_coverage(self): + ok, failures = REPORT.validate_junit( + '7.16.0', catalog_results_with_solana_lut_skipped('7.16.0'), + 'full') + self.assertFalse(ok) + self.assertEqual(4, len(failures)) + self.assertTrue(all(item[3] == 'skipped-but-required' + for item in failures)) + + def test_bitcoin_only_accepts_absent_solana_lut_handlers(self): + result = REPORT.validate_junit( + '7.16.0', catalog_results_with_solana_lut_skipped('7.16.0'), + 'bitcoin-only') + self.assertEqual((True, []), result) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_sign_typed_data.py b/tests/test_sign_typed_data.py index d0994933..56183268 100644 --- a/tests/test_sign_typed_data.py +++ b/tests/test_sign_typed_data.py @@ -18,6 +18,7 @@ import common import binascii import json +import os import keepkeylib.messages_pb2 as proto import keepkeylib.messages_ethereum_pb2 as eth_proto @@ -110,7 +111,9 @@ def test_ethereum_sign_typed_data_hash(self): # cannot bind the hash to any typed data it displayed. Opt in explicitly # rather than having the firmware relax the gate. self.client.apply_policy("AdvancedMode", 1) - with open('sign_typed_data.json') as f: + fixture_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'sign_typed_data.json') + with open(fixture_path, encoding="utf-8") as f: txtests = json.load(f) def sign(test): diff --git a/tests/test_storage_version_gate.py b/tests/test_storage_version_gate.py index b2e1ae08..cf1b5019 100644 --- a/tests/test_storage_version_gate.py +++ b/tests/test_storage_version_gate.py @@ -493,6 +493,7 @@ def __init__(self, workdir): self.port = _free_port_pair() self.img = os.path.join(workdir, "emulator.img") self.proc = None + self._endpoint_lease = None # -- process ------------------------------------------------------------ @@ -514,15 +515,22 @@ def boot(self): self.proc = subprocess.Popen( [_EMULATOR_BIN], cwd=self.workdir, env=env, stdout=log, stderr=subprocess.STDOUT) - for _ in range(100): - time.sleep(0.1) - if self.proc.poll() is not None: - raise RuntimeError( - "emulator exited rc=%s before answering; see %s" - % (self.proc.returncode, os.path.join(self.workdir, "emu.log"))) - if self._ping(): - return - raise RuntimeError("emulator did not answer PINGPING on port %d" % self.port) + from emulator_endpoints import owned_emulator_pair + try: + self._endpoint_lease = owned_emulator_pair(self.port) + self._endpoint_lease.__enter__() + for _ in range(100): + time.sleep(0.1) + if self.proc.poll() is not None: + raise RuntimeError( + "emulator exited rc=%s before answering; see %s" + % (self.proc.returncode, os.path.join(self.workdir, "emu.log"))) + if self._ping(): + return + raise RuntimeError("emulator did not answer PINGPING on port %d" % self.port) + except BaseException: + self.halt() + raise def halt(self): """Power cycle, not a graceful shutdown -- flash keeps whatever @@ -537,6 +545,9 @@ def halt(self): self.proc.kill() self.proc.wait() self.proc = None + if self._endpoint_lease is not None: + self._endpoint_lease.__exit__(None, None, None) + self._endpoint_lease = None time.sleep(0.2) # -- client ------------------------------------------------------------- @@ -606,6 +617,20 @@ def patch(self, off, rel, data): with open(self.img, "r+b") as f: f.seek(off + rel) f.write(data) + # These edits construct alternate-version fixtures, not corrupt + # records. Preserve the optional durable-commit envelope so boot + # reaches the version reader rather than rejecting a stale CRC. + f.seek(off) + record = f.read(2580) + if record[2572:2576] == b"crc1": + crc = 0xffffffff + for (word,) in struct.iter_unpack(".+)_tx_(?P[0-9a-f]{64})\.json$" +) + +NETWORK_IMPORT_ALLOWLIST = { + "conftest.py": {"requests", "socket", "urllib"}, + # Negative control: these APIs must be imported so the autouse fixture can + # prove every non-emulator transport is rejected at runtime. + "test_network_policy.py": {"requests", "socket"}, + "test_storage_version_gate.py": {"socket"}, + "test_tx_fixture_integrity.py": {"requests", "socket"}, +} + + +def validate_test_network_surface(tests_dir): + """Reject live-network helpers, including files pytest would not collect.""" + violations = [] + for path in sorted(Path(tests_dir).rglob("*.py")): + relative = path.relative_to(tests_dir).as_posix() + allowed = NETWORK_IMPORT_ALLOWLIST.get(relative, set()) + tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) + for node in ast.walk(tree): + imports = [] + if isinstance(node, ast.Import): + imports = [alias.name.split(".", 1)[0] for alias in node.names] + elif isinstance(node, ast.ImportFrom) and node.module: + imports = [node.module.split(".", 1)[0]] + for imported in imports: + if imported in {"http", "requests", "socket", "urllib"} and \ + imported not in allowed: + violations.append("%s:%s imports %s" % + (relative, node.lineno, imported)) + if violations: + raise ValueError( + "unauthorized network-capable code under tests/: %s" % + "; ".join(violations)) + + +def _varint(value): + if value < 253: + return struct.pack("= 128: + b.append((x & 127) | 128) + x >>= 7 + b.append(x) + return bytes(b) + + +auth = ( + struct.pack('8} - {status.upper()}") - - -if __name__ == "__main__": - try: - main() - except Exception as e: - print(f"Error: {e}", file=sys.stderr) - sys.exit(1)